* [PATCH 01/43] rc-core: move timeout and checks to lirc
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
@ 2012-05-23 9:42 ` David Härdeman
2012-05-23 9:42 ` [PATCH 02/43] rc-core: add separate defines for protocol bitmaps and numbers David Härdeman
` (42 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:42 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
The lirc TX functionality expects the process which writes (TX) data to
the lirc dev to sleep until the actual data has been transmitted by the
hardware.
Since the same timeout calculation is duplicated in more than one driver
(and would have to be duplicated in even more drivers as they gain TX
support), it makes sense to move this timeout calculation to the lirc
layer instead.
Also, the upcoming rc-core layer will not provide the same behaviour, it
will return as soon as all data is buffered in a TX kfifo which lets
userspace get on with its business.
At the same time, centralize some of the sanity checks.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/ir-lirc-codec.c | 33 +++++++++++++++++++++++++++++----
drivers/media/rc/mceusb.c | 18 ------------------
drivers/media/rc/rc-loopback.c | 12 ------------
3 files changed, 29 insertions(+), 34 deletions(-)
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 5faba2a..0287716 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -107,6 +107,12 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
unsigned int *txbuf; /* buffer with values to transmit */
ssize_t ret = 0;
size_t count;
+ ktime_t start;
+ s64 towait;
+ unsigned int duration = 0; /* signal duration in us */
+ int i;
+
+ start = ktime_get();
lirc = lirc_get_pdata(file);
if (!lirc)
@@ -129,11 +135,30 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
goto out;
}
- if (dev->tx_ir)
- ret = dev->tx_ir(dev, txbuf, count);
+ if (!dev->tx_ir) {
+ ret = -ENOSYS;
+ goto out;
+ }
+
+ ret = dev->tx_ir(dev, txbuf, (u32)count);
+ if (ret < 0)
+ goto out;
+
+ for (i = 0; i < ret; i++)
+ duration += txbuf[i];
- if (ret > 0)
- ret *= sizeof(unsigned);
+ ret *= sizeof(unsigned int);
+
+ /*
+ * The lircd gap calculation expects the write function to
+ * wait for the actual IR signal to be transmitted before
+ * returning.
+ */
+ towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get());
+ if (towait > 0) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(towait));
+ }
out:
kfree(txbuf);
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 84e06d3..6e430dd 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -786,10 +786,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
int i, ret = 0;
int cmdcount = 0;
unsigned char *cmdbuf; /* MCE command buffer */
- long signal_duration = 0; /* Singnal length in us */
- struct timeval start_time, end_time;
-
- do_gettimeofday(&start_time);
cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL);
if (!cmdbuf)
@@ -802,7 +798,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
/* Generate mce packet data */
for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
- signal_duration += txbuf[i];
txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
@@ -845,19 +840,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
/* Transmit the command to the mce device */
mce_async_out(ir, cmdbuf, cmdcount);
- /*
- * The lircd gap calculation expects the write function to
- * wait the time it takes for the ircommand to be sent before
- * it returns.
- */
- do_gettimeofday(&end_time);
- signal_duration -= (end_time.tv_usec - start_time.tv_usec) +
- (end_time.tv_sec - start_time.tv_sec) * 1000000;
-
- /* delay with the closest number of ticks */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(usecs_to_jiffies(signal_duration));
-
out:
kfree(cmdbuf);
return ret ? ret : count;
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index fae1615..f9be681 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -105,18 +105,9 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
{
struct loopback_dev *lodev = dev->priv;
u32 rxmask;
- unsigned total_duration = 0;
unsigned i;
DEFINE_IR_RAW_EVENT(rawir);
- for (i = 0; i < count; i++)
- total_duration += abs(txbuf[i]);
-
- if (total_duration == 0) {
- dprintk("invalid tx data, total duration zero\n");
- return -EINVAL;
- }
-
if (lodev->txcarrier < lodev->rxcarriermin ||
lodev->txcarrier > lodev->rxcarriermax) {
dprintk("ignoring tx, carrier out of range\n");
@@ -148,9 +139,6 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
ir_raw_event_handle(dev);
out:
- /* Lirc expects this function to take as long as the total duration */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(usecs_to_jiffies(total_duration));
return count;
}
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 02/43] rc-core: add separate defines for protocol bitmaps and numbers
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
2012-05-23 9:42 ` [PATCH 01/43] rc-core: move timeout and checks to lirc David Härdeman
@ 2012-05-23 9:42 ` David Härdeman
2012-05-23 9:42 ` [PATCH 03/43] rc-core: don't throw away protocol information David Härdeman
` (41 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:42 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
The RC_TYPE_* defines are currently used both where a single protocol is
expected and where a bitmap of protocols is expected. This patch tries
to separate the two in preparation for the following patches.
The intended use is also clearer to anyone reading the code. Where a
single protocol is expected, enum rc_type is used, where one or more
protocol(s) are expected, something like u64 is used.
The format of the sysfs "protocols" file is slightly changed by
this patch, but it should still accept the same protocol names
as before, it's only the output that is more specific.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/dvb/dvb-usb/af9015.c | 12 +-
drivers/media/dvb/dvb-usb/af9035.c | 4 -
drivers/media/dvb/dvb-usb/anysee.c | 2
drivers/media/dvb/dvb-usb/az6007.c | 2
drivers/media/dvb/dvb-usb/dib0700_core.c | 9 +
drivers/media/dvb/dvb-usb/dib0700_devices.c | 146 ++++++++++++------------
drivers/media/dvb/dvb-usb/it913x.c | 4 -
drivers/media/dvb/dvb-usb/lmedm04.c | 8 +
drivers/media/dvb/dvb-usb/pctv452e.c | 4 -
drivers/media/dvb/dvb-usb/rtl28xxu.c | 8 +
drivers/media/dvb/dvb-usb/technisat-usb2.c | 2
drivers/media/dvb/dvb-usb/ttusb2.c | 2
drivers/media/dvb/mantis/mantis_input.c | 2
drivers/media/dvb/siano/smsir.c | 2
drivers/media/rc/ati_remote.c | 2
drivers/media/rc/ene_ir.c | 2
drivers/media/rc/fintek-cir.c | 2
drivers/media/rc/gpio-ir-recv.c | 2
drivers/media/rc/imon.c | 27 ++--
drivers/media/rc/ir-jvc-decoder.c | 4 -
drivers/media/rc/ir-lirc-codec.c | 4 -
drivers/media/rc/ir-mce_kbd-decoder.c | 4 -
drivers/media/rc/ir-nec-decoder.c | 4 -
drivers/media/rc/ir-rc5-decoder.c | 14 ++
drivers/media/rc/ir-rc5-sz-decoder.c | 6 -
drivers/media/rc/ir-rc6-decoder.c | 8 +
drivers/media/rc/ir-sanyo-decoder.c | 4 -
drivers/media/rc/ir-sony-decoder.c | 17 ++-
drivers/media/rc/ite-cir.c | 2
drivers/media/rc/keymaps/rc-imon-mce.c | 2
drivers/media/rc/keymaps/rc-rc6-mce.c | 2
drivers/media/rc/mceusb.c | 2
drivers/media/rc/nuvoton-cir.c | 2
drivers/media/rc/rc-loopback.c | 2
drivers/media/rc/rc-main.c | 79 ++++++++-----
drivers/media/rc/redrat3.c | 2
drivers/media/rc/streamzap.c | 2
drivers/media/video/cx18/cx18-i2c.c | 2
drivers/media/video/cx231xx/cx231xx-input.c | 2
drivers/media/video/cx23885/cx23885-input.c | 4 -
drivers/media/video/cx88/cx88-input.c | 8 +
drivers/media/video/em28xx/em28xx-input.c | 10 +-
drivers/media/video/hdpvr/hdpvr-i2c.c | 2
drivers/media/video/ir-kbd-i2c.c | 14 +-
drivers/media/video/ivtv/ivtv-i2c.c | 8 +
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 4 -
drivers/media/video/saa7134/saa7134-input.c | 2
drivers/media/video/tm6000/tm6000-input.c | 16 +--
include/media/ir-kbd-i2c.h | 2
include/media/rc-core.h | 2
include/media/rc-map.h | 64 ++++++++---
51 files changed, 308 insertions(+), 234 deletions(-)
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 677fed7..5395c6a 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -1576,11 +1576,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
.rc.core = {
- .protocol = RC_TYPE_NEC,
+ .protocol = RC_BIT_NEC,
.module_name = "af9015",
.rc_query = af9015_rc_query,
.rc_interval = AF9015_RC_INTERVAL,
- .allowed_protos = RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_NEC,
},
.i2c_algo = &af9015_i2c_algo,
@@ -1712,11 +1712,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
.rc.core = {
- .protocol = RC_TYPE_NEC,
+ .protocol = RC_BIT_NEC,
.module_name = "af9015",
.rc_query = af9015_rc_query,
.rc_interval = AF9015_RC_INTERVAL,
- .allowed_protos = RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_NEC,
},
.i2c_algo = &af9015_i2c_algo,
@@ -1837,11 +1837,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
.rc.core = {
- .protocol = RC_TYPE_NEC,
+ .protocol = RC_BIT_NEC,
.module_name = "af9015",
.rc_query = af9015_rc_query,
.rc_interval = AF9015_RC_INTERVAL,
- .allowed_protos = RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_NEC,
},
.i2c_algo = &af9015_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c
index e83b39d..d7c7c17 100644
--- a/drivers/media/dvb/dvb-usb/af9035.c
+++ b/drivers/media/dvb/dvb-usb/af9035.c
@@ -666,8 +666,8 @@ static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
d->props.rc.core.allowed_protos = RC_TYPE_NEC;
break;
case 1: /* RC6 */
- d->props.rc.core.protocol = RC_TYPE_RC6;
- d->props.rc.core.allowed_protos = RC_TYPE_RC6;
+ d->props.rc.core.protocol = RC_TYPE_RC6_MCE;
+ d->props.rc.core.allowed_protos = RC_TYPE_RC6_MCE;
break;
}
d->props.rc.core.rc_query = af9035_rc_query;
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index 03c2865..f510f91 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -1371,7 +1371,7 @@ static struct dvb_usb_device_properties anysee_properties = {
.rc.core = {
.rc_codes = RC_MAP_ANYSEE,
- .protocol = RC_TYPE_OTHER,
+ .protocol = RC_BIT_OTHER,
.module_name = "anysee",
.rc_query = anysee_rc_query,
.rc_interval = 250, /* windows driver uses 500ms */
diff --git a/drivers/media/dvb/dvb-usb/az6007.c b/drivers/media/dvb/dvb-usb/az6007.c
index 4008b9c..102114e 100644
--- a/drivers/media/dvb/dvb-usb/az6007.c
+++ b/drivers/media/dvb/dvb-usb/az6007.c
@@ -899,7 +899,7 @@ static struct dvb_usb_device_properties az6007_properties = {
.rc_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
.module_name = "az6007",
.rc_query = az6007_rc_query,
- .allowed_protos = RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_NEC,
},
.i2c_algo = &az6007_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 7e9e00f..192d805 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -621,16 +621,15 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
st->buf[2] = 0;
/* Set the IR mode */
- if (rc_type == RC_TYPE_RC5)
+ if (rc_type == RC_BIT_RC5)
new_proto = 1;
- else if (rc_type == RC_TYPE_NEC)
+ else if (rc_type == RC_BIT_NEC)
new_proto = 0;
- else if (rc_type == RC_TYPE_RC6) {
+ else if (rc_type == RC_BIT_RC6_MCE) {
if (st->fw_version < 0x10200) {
ret = -EINVAL;
goto out;
}
-
new_proto = 2;
} else {
ret = -EINVAL;
@@ -707,7 +706,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
purb->actual_length);
switch (d->props.rc.core.protocol) {
- case RC_TYPE_NEC:
+ case RC_BIT_NEC:
toggle = 0;
/* NEC protocol sends repeat code as 0 0 0 FF */
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 510001d..1179842 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -518,7 +518,7 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
d->last_event = 0;
switch (d->props.rc.core.protocol) {
- case RC_TYPE_NEC:
+ case RC_BIT_NEC:
/* NEC protocol sends repeat code as 0 0 0 FF */
if ((key[3-2] == 0x00) && (key[3-3] == 0x00) &&
(key[3] == 0xff))
@@ -3658,9 +3658,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -3698,9 +3698,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -3763,9 +3763,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -3808,9 +3808,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -3890,9 +3890,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -3936,9 +3936,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -3987,9 +3987,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4055,9 +4055,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4106,9 +4106,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_NEC_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4177,9 +4177,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4215,9 +4215,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4295,9 +4295,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4341,9 +4341,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_NEC_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4394,9 +4394,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4433,9 +4433,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4472,9 +4472,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4511,9 +4511,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4550,9 +4550,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4589,9 +4589,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4644,9 +4644,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4681,9 +4681,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4721,9 +4721,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4761,9 +4761,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -4802,9 +4802,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
.module_name = "dib0700",
.rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_TYPE_RC5 |
- RC_TYPE_RC6 |
- RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_RC5 |
+ RC_BIT_RC6_MCE |
+ RC_BIT_NEC,
.change_protocol = dib0700_change_protocol,
},
},
diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c
index 6244fe9..e54f3dc 100644
--- a/drivers/media/dvb/dvb-usb/it913x.c
+++ b/drivers/media/dvb/dvb-usb/it913x.c
@@ -888,11 +888,11 @@ static struct dvb_usb_device_properties it913x_properties = {
},
.identify_state = it913x_identify_state,
.rc.core = {
- .protocol = RC_TYPE_NEC,
+ .protocol = RC_BIT_NEC,
.module_name = "it913x",
.rc_query = it913x_rc_query,
.rc_interval = IT913X_POLL,
- .allowed_protos = RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_NEC,
.rc_codes = RC_MAP_IT913X_V1,
},
.i2c_algo = &it913x_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c
index 25d1031..8ff161e 100644
--- a/drivers/media/dvb/dvb-usb/lmedm04.c
+++ b/drivers/media/dvb/dvb-usb/lmedm04.c
@@ -1279,9 +1279,9 @@ static struct dvb_usb_device_properties lme2510_properties = {
}
},
.rc.core = {
- .protocol = RC_TYPE_NEC,
+ .protocol = RC_BIT_NEC,
.module_name = "LME2510 Remote Control",
- .allowed_protos = RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_NEC,
.rc_codes = RC_MAP_LME2510,
},
.power_ctrl = lme2510_powerup,
@@ -1330,9 +1330,9 @@ static struct dvb_usb_device_properties lme2510c_properties = {
}
},
.rc.core = {
- .protocol = RC_TYPE_NEC,
+ .protocol = RC_BIT_NEC,
.module_name = "LME2510 Remote Control",
- .allowed_protos = RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_NEC,
.rc_codes = RC_MAP_LME2510,
},
.power_ctrl = lme2510_powerup,
diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c
index f526eb0..6eefd4e 100644
--- a/drivers/media/dvb/dvb-usb/pctv452e.c
+++ b/drivers/media/dvb/dvb-usb/pctv452e.c
@@ -928,7 +928,7 @@ static struct dvb_usb_device_properties pctv452e_properties = {
.rc.core = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
- .allowed_protos = RC_TYPE_UNKNOWN,
+ .allowed_protos = RC_BIT_UNKNOWN,
.rc_query = pctv452e_rc_query,
.rc_interval = 100,
},
@@ -981,7 +981,7 @@ static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
.rc.core = {
.rc_codes = RC_MAP_TT_1500,
- .allowed_protos = RC_TYPE_UNKNOWN,
+ .allowed_protos = RC_BIT_UNKNOWN,
.rc_query = pctv452e_rc_query,
.rc_interval = 100,
},
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c
index 41e1f55..1abd247 100644
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.c
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c
@@ -824,11 +824,11 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
.power_ctrl = rtl28xxu_power_ctrl,
.rc.core = {
- .protocol = RC_TYPE_NEC,
+ .protocol = RC_BIT_NEC,
.module_name = "rtl28xxu",
.rc_query = rtl2831u_rc_query,
.rc_interval = 400,
- .allowed_protos = RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_NEC,
.rc_codes = RC_MAP_EMPTY,
},
@@ -886,11 +886,11 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
.power_ctrl = rtl28xxu_power_ctrl,
.rc.core = {
- .protocol = RC_TYPE_NEC,
+ .protocol = RC_BIT_NEC,
.module_name = "rtl28xxu",
.rc_query = rtl2832u_rc_query,
.rc_interval = 400,
- .allowed_protos = RC_TYPE_NEC,
+ .allowed_protos = RC_BIT_NEC,
.rc_codes = RC_MAP_EMPTY,
},
diff --git a/drivers/media/dvb/dvb-usb/technisat-usb2.c b/drivers/media/dvb/dvb-usb/technisat-usb2.c
index acefaa8..3b8752a 100644
--- a/drivers/media/dvb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/dvb/dvb-usb/technisat-usb2.c
@@ -731,7 +731,7 @@ static struct dvb_usb_device_properties technisat_usb2_devices = {
.rc_codes = RC_MAP_TECHNISAT_USB2,
.module_name = "technisat-usb2",
.rc_query = technisat_usb2_rc_query,
- .allowed_protos = RC_TYPE_ALL,
+ .allowed_protos = RC_BIT_ALL,
.driver_type = RC_DRIVER_IR_RAW,
}
};
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c
index e53a106..c5be462 100644
--- a/drivers/media/dvb/dvb-usb/ttusb2.c
+++ b/drivers/media/dvb/dvb-usb/ttusb2.c
@@ -741,7 +741,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
.rc_interval = 150, /* Less than IR_KEYPRESS_TIMEOUT */
.rc_codes = RC_MAP_TT_1500,
.rc_query = tt3650_rc_query,
- .allowed_protos = RC_TYPE_UNKNOWN,
+ .allowed_protos = RC_BIT_UNKNOWN,
},
.num_adapters = 1,
diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c
index db6d54d..8efd971 100644
--- a/drivers/media/dvb/mantis/mantis_input.c
+++ b/drivers/media/dvb/mantis/mantis_input.c
@@ -99,7 +99,7 @@ static struct rc_map_list ir_mantis_map = {
.map = {
.scan = mantis_ir_table,
.size = ARRAY_SIZE(mantis_ir_table),
- .rc_type = RC_TYPE_UNKNOWN,
+ .rc_type = RC_BIT_UNKNOWN,
.name = RC_MAP_MANTIS,
}
};
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
index 37bc5c4..b8c5cad 100644
--- a/drivers/media/dvb/siano/smsir.c
+++ b/drivers/media/dvb/siano/smsir.c
@@ -88,7 +88,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
dev->priv = coredev;
dev->driver_type = RC_DRIVER_IR_RAW;
- dev->allowed_protos = RC_TYPE_ALL;
+ dev->allowed_protos = RC_BIT_ALL;
dev->map_name = sms_get_board(board_id)->rc_codes;
dev->driver_name = MODULE_NAME;
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 7be377f..dfeabd7 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -771,7 +771,7 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote)
rdev->priv = ati_remote;
rdev->driver_type = RC_DRIVER_SCANCODE;
- rdev->allowed_protos = RC_TYPE_OTHER;
+ rdev->allowed_protos = RC_BIT_OTHER;
rdev->driver_name = "ati_remote";
rdev->open = ati_remote_rc_open;
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index bef5296..10621dc 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -1041,7 +1041,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
learning_mode_force = false;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rdev->allowed_protos = RC_TYPE_ALL;
+ rdev->allowed_protos = RC_BIT_ALL;
rdev->priv = dev;
rdev->open = ene_open;
rdev->close = ene_close;
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index 6aabf7a..f684dd8 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -532,7 +532,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
/* Set up the rc device */
rdev->priv = fintek;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rdev->allowed_protos = RC_TYPE_ALL;
+ rdev->allowed_protos = RC_BIT_ALL;
rdev->open = fintek_open;
rdev->close = fintek_close;
rdev->input_name = FINTEK_DESCRIPTION;
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 0d87545..478b2e9 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -83,7 +83,7 @@ static int __devinit gpio_ir_recv_probe(struct platform_device *pdev)
}
rcdev->driver_type = RC_DRIVER_IR_RAW;
- rcdev->allowed_protos = RC_TYPE_ALL;
+ rcdev->allowed_protos = RC_BIT_ALL;
rcdev->input_name = GPIO_IR_DEVICE_NAME;
rcdev->input_id.bustype = BUS_HOST;
rcdev->driver_name = GPIO_IR_DRIVER_NAME;
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 5dd0386..24eb493 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -1015,17 +1015,16 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
"this device does not support\n");
switch (rc_type) {
- case RC_TYPE_RC6:
+ case RC_BIT_RC6_MCE:
dev_dbg(dev, "Configuring IR receiver for MCE protocol\n");
ir_proto_packet[0] = 0x01;
break;
- case RC_TYPE_UNKNOWN:
- case RC_TYPE_OTHER:
+ case RC_BIT_OTHER:
dev_dbg(dev, "Configuring IR receiver for iMON protocol\n");
if (!pad_stabilize)
dev_dbg(dev, "PAD stabilize functionality disabled\n");
/* ir_proto_packet[0] = 0x00; // already the default */
- rc_type = RC_TYPE_OTHER;
+ rc_type = RC_BIT_OTHER;
break;
default:
dev_warn(dev, "Unsupported IR protocol specified, overriding "
@@ -1033,7 +1032,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
if (!pad_stabilize)
dev_dbg(dev, "PAD stabilize functionality disabled\n");
/* ir_proto_packet[0] = 0x00; // already the default */
- rc_type = RC_TYPE_OTHER;
+ rc_type = RC_BIT_OTHER;
break;
}
@@ -1323,7 +1322,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
rel_x = buf[2];
rel_y = buf[3];
- if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) {
+ if (ictx->rc_type == RC_BIT_OTHER && pad_stabilize) {
if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) {
dir = stabilize((int)rel_x, (int)rel_y,
timeout, threshold);
@@ -1390,7 +1389,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
buf[0] = 0x01;
buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0;
- if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) {
+ if (ictx->rc_type == RC_BIT_OTHER && pad_stabilize) {
dir = stabilize((int)rel_x, (int)rel_y,
timeout, threshold);
if (!dir) {
@@ -1511,7 +1510,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
kc = imon_panel_key_lookup(scancode);
} else {
scancode = be32_to_cpu(*((u32 *)buf));
- if (ictx->rc_type == RC_TYPE_RC6) {
+ if (ictx->rc_type == RC_BIT_RC6_MCE) {
ktype = IMON_KEY_IMON;
if (buf[0] == 0x80)
ktype = IMON_KEY_MCE;
@@ -1744,7 +1743,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
{
u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
- u64 allowed_protos = RC_TYPE_OTHER;
+ u64 allowed_protos = RC_BIT_OTHER;
switch (ffdc_cfg_byte) {
/* iMON Knob, no display, iMON IR + vol knob */
@@ -1775,13 +1774,13 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
case 0x9e:
dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR");
detected_display_type = IMON_DISPLAY_TYPE_VFD;
- allowed_protos = RC_TYPE_RC6;
+ allowed_protos = RC_BIT_RC6_MCE;
break;
/* iMON LCD, MCE IR */
case 0x9f:
dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
detected_display_type = IMON_DISPLAY_TYPE_LCD;
- allowed_protos = RC_TYPE_RC6;
+ allowed_protos = RC_BIT_RC6_MCE;
break;
default:
dev_info(ictx->dev, "Unknown 0xffdc device, "
@@ -1789,7 +1788,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
detected_display_type = IMON_DISPLAY_TYPE_VFD;
/* We don't know which one it is, allow user to set the
* RC6 one from userspace if OTHER wasn't correct. */
- allowed_protos |= RC_TYPE_RC6;
+ allowed_protos |= RC_BIT_RC6_MCE;
break;
}
@@ -1875,7 +1874,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
rdev->priv = ictx;
rdev->driver_type = RC_DRIVER_SCANCODE;
- rdev->allowed_protos = RC_TYPE_OTHER | RC_TYPE_RC6; /* iMON PAD or MCE */
+ rdev->allowed_protos = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */
rdev->change_protocol = imon_ir_change_protocol;
rdev->driver_name = MOD_NAME;
@@ -1893,7 +1892,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
imon_set_display_type(ictx);
- if (ictx->rc_type == RC_TYPE_RC6)
+ if (ictx->rc_type == RC_BIT_RC6_MCE)
rdev->map_name = RC_MAP_IMON_MCE;
else
rdev->map_name = RC_MAP_IMON_PAD;
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 035668e..69edffb 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -47,7 +47,7 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
struct jvc_dec *data = &dev->raw->jvc;
- if (!(dev->raw->enabled_protocols & RC_TYPE_JVC))
+ if (!(dev->raw->enabled_protocols & RC_BIT_JVC))
return 0;
if (!is_timing_event(ev)) {
@@ -174,7 +174,7 @@ out:
}
static struct ir_raw_handler jvc_handler = {
- .protocols = RC_TYPE_JVC,
+ .protocols = RC_BIT_JVC,
.decode = ir_jvc_decode,
};
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 0287716..439879c 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -35,7 +35,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
struct lirc_codec *lirc = &dev->raw->lirc;
int sample;
- if (!(dev->raw->enabled_protocols & RC_TYPE_LIRC))
+ if (!(dev->raw->enabled_protocols & RC_BIT_LIRC))
return 0;
if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf)
@@ -408,7 +408,7 @@ static int ir_lirc_unregister(struct rc_dev *dev)
}
static struct ir_raw_handler lirc_handler = {
- .protocols = RC_TYPE_LIRC,
+ .protocols = RC_BIT_LIRC,
.decode = ir_lirc_decode,
.raw_register = ir_lirc_register,
.raw_unregister = ir_lirc_unregister,
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 3784ebf..33fafa4 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -216,7 +216,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
unsigned long delay;
- if (!(dev->raw->enabled_protocols & RC_TYPE_MCE_KBD))
+ if (!(dev->raw->enabled_protocols & RC_BIT_MCE_KBD))
return 0;
if (!is_timing_event(ev)) {
@@ -422,7 +422,7 @@ static int ir_mce_kbd_unregister(struct rc_dev *dev)
}
static struct ir_raw_handler mce_kbd_handler = {
- .protocols = RC_TYPE_MCE_KBD,
+ .protocols = RC_BIT_MCE_KBD,
.decode = ir_mce_kbd_decode,
.raw_register = ir_mce_kbd_register,
.raw_unregister = ir_mce_kbd_unregister,
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 3c9431a..dc21a67 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -52,7 +52,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 address, not_address, command, not_command;
bool send_32bits = false;
- if (!(dev->raw->enabled_protocols & RC_TYPE_NEC))
+ if (!(dev->raw->enabled_protocols & RC_BIT_NEC))
return 0;
if (!is_timing_event(ev)) {
@@ -201,7 +201,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
static struct ir_raw_handler nec_handler = {
- .protocols = RC_TYPE_NEC,
+ .protocols = RC_BIT_NEC,
.decode = ir_nec_decode,
};
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 9ab663a..5b4d1dd 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -52,8 +52,8 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 toggle;
u32 scancode;
- if (!(dev->raw->enabled_protocols & RC_TYPE_RC5))
- return 0;
+ if (!(dev->raw->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X)))
+ return 0;
if (!is_timing_event(ev)) {
if (ev.reset)
@@ -128,6 +128,10 @@ again:
if (data->wanted_bits == RC5X_NBITS) {
/* RC5X */
u8 xdata, command, system;
+ if (!(dev->raw->enabled_protocols & RC_BIT_RC5X)) {
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
xdata = (data->bits & 0x0003F) >> 0;
command = (data->bits & 0x00FC0) >> 6;
system = (data->bits & 0x1F000) >> 12;
@@ -141,6 +145,10 @@ again:
} else {
/* RC5 */
u8 command, system;
+ if (!(dev->raw->enabled_protocols & RC_BIT_RC5)) {
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
command = (data->bits & 0x0003F) >> 0;
system = (data->bits & 0x007C0) >> 6;
toggle = (data->bits & 0x00800) ? 1 : 0;
@@ -164,7 +172,7 @@ out:
}
static struct ir_raw_handler rc5_handler = {
- .protocols = RC_TYPE_RC5,
+ .protocols = RC_BIT_RC5 | RC_BIT_RC5X,
.decode = ir_rc5_decode,
};
diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c
index ec8d4a2..fd807a8 100644
--- a/drivers/media/rc/ir-rc5-sz-decoder.c
+++ b/drivers/media/rc/ir-rc5-sz-decoder.c
@@ -48,8 +48,8 @@ static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 toggle, command, system;
u32 scancode;
- if (!(dev->raw->enabled_protocols & RC_TYPE_RC5_SZ))
- return 0;
+ if (!(dev->raw->enabled_protocols & RC_BIT_RC5_SZ))
+ return 0;
if (!is_timing_event(ev)) {
if (ev.reset)
@@ -128,7 +128,7 @@ out:
}
static struct ir_raw_handler rc5_sz_handler = {
- .protocols = RC_TYPE_RC5_SZ,
+ .protocols = RC_BIT_RC5_SZ,
.decode = ir_rc5_sz_decode,
};
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index 4cfdd7f..e19072f 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -89,7 +89,9 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
u8 toggle;
- if (!(dev->raw->enabled_protocols & RC_TYPE_RC6))
+ if (!(dev->raw->enabled_protocols &
+ (RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 |
+ RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE)))
return 0;
if (!is_timing_event(ev)) {
@@ -271,7 +273,9 @@ out:
}
static struct ir_raw_handler rc6_handler = {
- .protocols = RC_TYPE_RC6,
+ .protocols = RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 |
+ RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 |
+ RC_BIT_RC6_MCE,
.decode = ir_rc6_decode,
};
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index 7e54ec5..7e69a3b 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -58,7 +58,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
u8 address, command, not_command;
- if (!(dev->raw->enabled_protocols & RC_TYPE_SANYO))
+ if (!(dev->raw->enabled_protocols & RC_BIT_SANYO))
return 0;
if (!is_timing_event(ev)) {
@@ -179,7 +179,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
static struct ir_raw_handler sanyo_handler = {
- .protocols = RC_TYPE_SANYO,
+ .protocols = RC_BIT_SANYO,
.decode = ir_sanyo_decode,
};
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index dab98b3..fb91434 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -45,7 +45,8 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
u8 device, subdevice, function;
- if (!(dev->raw->enabled_protocols & RC_TYPE_SONY))
+ if (!(dev->raw->enabled_protocols &
+ (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20)))
return 0;
if (!is_timing_event(ev)) {
@@ -123,16 +124,28 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
switch (data->count) {
case 12:
+ if (!(dev->raw->enabled_protocols & RC_BIT_SONY12)) {
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
device = bitrev8((data->bits << 3) & 0xF8);
subdevice = 0;
function = bitrev8((data->bits >> 4) & 0xFE);
break;
case 15:
+ if (!(dev->raw->enabled_protocols & RC_BIT_SONY15)) {
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
device = bitrev8((data->bits >> 0) & 0xFF);
subdevice = 0;
function = bitrev8((data->bits >> 7) & 0xFE);
break;
case 20:
+ if (!(dev->raw->enabled_protocols & RC_BIT_SONY20)) {
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
device = bitrev8((data->bits >> 5) & 0xF8);
subdevice = bitrev8((data->bits >> 0) & 0xFF);
function = bitrev8((data->bits >> 12) & 0xFE);
@@ -157,7 +170,7 @@ out:
}
static struct ir_raw_handler sony_handler = {
- .protocols = RC_TYPE_SONY,
+ .protocols = RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20,
.decode = ir_sony_decode,
};
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 36fe5a3..494801e 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1562,7 +1562,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
/* set up ir-core props */
rdev->priv = itdev;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rdev->allowed_protos = RC_TYPE_ALL;
+ rdev->allowed_protos = RC_BIT_ALL;
rdev->open = ite_open;
rdev->close = ite_close;
rdev->s_idle = ite_s_idle;
diff --git a/drivers/media/rc/keymaps/rc-imon-mce.c b/drivers/media/rc/keymaps/rc-imon-mce.c
index 124c722..f0da960 100644
--- a/drivers/media/rc/keymaps/rc-imon-mce.c
+++ b/drivers/media/rc/keymaps/rc-imon-mce.c
@@ -121,7 +121,7 @@ static struct rc_map_list imon_mce_map = {
.scan = imon_mce,
.size = ARRAY_SIZE(imon_mce),
/* its RC6, but w/a hardware decoder */
- .rc_type = RC_TYPE_RC6,
+ .rc_type = RC_TYPE_RC6_MCE,
.name = RC_MAP_IMON_MCE,
}
};
diff --git a/drivers/media/rc/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c
index 753e43e..ef4006f 100644
--- a/drivers/media/rc/keymaps/rc-rc6-mce.c
+++ b/drivers/media/rc/keymaps/rc-rc6-mce.c
@@ -97,7 +97,7 @@ static struct rc_map_list rc6_mce_map = {
.map = {
.scan = rc6_mce,
.size = ARRAY_SIZE(rc6_mce),
- .rc_type = RC_TYPE_RC6,
+ .rc_type = RC_TYPE_RC6_MCE,
.name = RC_MAP_RC6_MCE,
}
};
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 6e430dd..f0f053d 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -1196,7 +1196,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
rc->dev.parent = dev;
rc->priv = ir;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc->allowed_protos = RC_TYPE_ALL;
+ rc->allowed_protos = RC_BIT_ALL;
rc->timeout = MS_TO_NS(100);
if (!ir->flags.no_tx) {
rc->s_tx_mask = mceusb_set_tx_mask;
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index dc8a7dd..f4ce071 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -1043,7 +1043,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
/* Set up the rc device */
rdev->priv = nvt;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rdev->allowed_protos = RC_TYPE_ALL;
+ rdev->allowed_protos = RC_BIT_ALL;
rdev->open = nvt_open;
rdev->close = nvt_close;
rdev->tx_ir = nvt_tx_ir;
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index f9be681..53d0282 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -195,7 +195,7 @@ static int __init loop_init(void)
rc->map_name = RC_MAP_EMPTY;
rc->priv = &loopdev;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc->allowed_protos = RC_TYPE_ALL;
+ rc->allowed_protos = RC_BIT_ALL;
rc->timeout = 100 * 1000 * 1000; /* 100 ms */
rc->min_timeout = 1;
rc->max_timeout = UINT_MAX;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 6e16b09..3455a9e 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -725,25 +725,47 @@ static struct class ir_input_class = {
.devnode = ir_devnode,
};
+/*
+ * These are the protocol textual descriptions that are
+ * used by the sysfs protocols file. Note that the order
+ * of the entries is relevant.
+ */
static struct {
u64 type;
char *name;
} proto_names[] = {
- { RC_TYPE_UNKNOWN, "unknown" },
- { RC_TYPE_RC5, "rc-5" },
- { RC_TYPE_NEC, "nec" },
- { RC_TYPE_RC6, "rc-6" },
- { RC_TYPE_JVC, "jvc" },
- { RC_TYPE_SONY, "sony" },
- { RC_TYPE_RC5_SZ, "rc-5-sz" },
- { RC_TYPE_SANYO, "sanyo" },
- { RC_TYPE_MCE_KBD, "mce_kbd" },
- { RC_TYPE_LIRC, "lirc" },
- { RC_TYPE_OTHER, "other" },
+ { RC_BIT_NONE, "none" },
+ { RC_BIT_OTHER, "other" },
+ { RC_BIT_UNKNOWN, "unknown" },
+ { RC_BIT_RC5, "rc-5:plain" },
+ { RC_BIT_RC5X, "rc-5:x" },
+ { RC_BIT_RC5_SZ, "rc-5:sz" },
+ { RC_BIT_RC5 |
+ RC_BIT_RC5X |
+ RC_BIT_RC5_SZ, "rc-5" },
+ { RC_BIT_RC6_0, "rc-6:0" },
+ { RC_BIT_RC6_6A_20, "rc-6:6a-20" },
+ { RC_BIT_RC6_6A_24, "rc-6:6a-24" },
+ { RC_BIT_RC6_6A_32, "rc-6:6a-32" },
+ { RC_BIT_RC6_MCE, "rc-6:mce" },
+ { RC_BIT_RC6_0 |
+ RC_BIT_RC6_6A_20 |
+ RC_BIT_RC6_6A_24 |
+ RC_BIT_RC6_6A_32 |
+ RC_BIT_RC6_MCE, "rc-6" },
+ { RC_BIT_JVC, "jvc" },
+ { RC_BIT_SONY12, "sony:12" },
+ { RC_BIT_SONY15, "sony:15" },
+ { RC_BIT_SONY20, "sony:20" },
+ { RC_BIT_SONY12 |
+ RC_BIT_SONY15 |
+ RC_BIT_SONY20, "sony" },
+ { RC_BIT_NEC, "nec" },
+ { RC_BIT_SANYO, "sanyo" },
+ { RC_BIT_MCE_KBD, "mce_kbd" },
+ { RC_BIT_LIRC, "lirc" },
};
-#define PROTO_NONE "none"
-
/**
* show_protocols() - shows the current IR protocol(s)
* @device: the device descriptor
@@ -789,6 +811,9 @@ static ssize_t show_protocols(struct device *device,
tmp += sprintf(tmp, "[%s] ", proto_names[i].name);
else if (allowed & proto_names[i].type)
tmp += sprintf(tmp, "%s ", proto_names[i].name);
+
+ if (allowed & proto_names[i].type)
+ allowed &= ~proto_names[i].type;
}
if (tmp != buf)
@@ -866,26 +891,20 @@ static ssize_t store_protocols(struct device *device,
disable = false;
}
- if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) {
- tmp += sizeof(PROTO_NONE);
- mask = 0;
- count++;
- } else {
- for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
- if (!strcasecmp(tmp, proto_names[i].name)) {
- tmp += strlen(proto_names[i].name);
- mask = proto_names[i].type;
- break;
- }
- }
- if (i == ARRAY_SIZE(proto_names)) {
- IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
- ret = -EINVAL;
- goto out;
+ for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
+ if (!strcasecmp(tmp, proto_names[i].name)) {
+ mask = proto_names[i].type;
+ break;
}
- count++;
}
+ if (i == ARRAY_SIZE(proto_names)) {
+ IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
+ return -EINVAL;
+ }
+
+ count++;
+
if (enable)
type |= mask;
else if (disable)
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 2878b0e..13a679f 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -1079,7 +1079,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
rc->dev.parent = dev;
rc->priv = rr3;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc->allowed_protos = RC_TYPE_ALL;
+ rc->allowed_protos = RC_BIT_ALL;
rc->timeout = US_TO_NS(2750);
rc->tx_ir = redrat3_transmit_ir;
rc->s_tx_carrier = redrat3_set_tx_carrier;
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index d6f4bfe..c720f12 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -322,7 +322,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
rdev->dev.parent = dev;
rdev->priv = sz;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rdev->allowed_protos = RC_TYPE_ALL;
+ rdev->allowed_protos = RC_BIT_ALL;
rdev->driver_name = DRIVER_NAME;
rdev->map_name = RC_MAP_STREAMZAP;
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 51609d5..4908eb7 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -98,7 +98,7 @@ static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw,
case CX18_HW_Z8F0811_IR_RX_HAUP:
init_data->ir_codes = RC_MAP_HAUPPAUGE;
init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
- init_data->type = RC_TYPE_RC5;
+ init_data->type = RC_BIT_RC5;
init_data->name = cx->card_name;
info.platform_data = init_data;
break;
diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c
index 96176e9..0f7b424 100644
--- a/drivers/media/video/cx231xx/cx231xx-input.c
+++ b/drivers/media/video/cx231xx/cx231xx-input.c
@@ -99,7 +99,7 @@ int cx231xx_ir_init(struct cx231xx *dev)
/* The i2c micro-controller only outputs the cmd part of NEC protocol */
dev->init_data.rc_dev->scanmask = 0xff;
dev->init_data.rc_dev->driver_name = "cx231xx";
- dev->init_data.type = RC_TYPE_NEC;
+ dev->init_data.type = RC_BIT_NEC;
info.addr = 0x30;
/* Load and bind ir-kbd-i2c */
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
index ce765e3..6aa96a2 100644
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -268,14 +268,14 @@ int cx23885_input_init(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1250:
/* Integrated CX2388[58] IR controller */
driver_type = RC_DRIVER_IR_RAW;
- allowed_protos = RC_TYPE_ALL;
+ allowed_protos = RC_BIT_ALL;
/* The grey Hauppauge RC-5 remote */
rc_map = RC_MAP_HAUPPAUGE;
break;
case CX23885_BOARD_TEVII_S470:
/* Integrated CX23885 IR controller */
driver_type = RC_DRIVER_IR_RAW;
- allowed_protos = RC_TYPE_ALL;
+ allowed_protos = RC_BIT_ALL;
/* A guess at the remote */
rc_map = RC_MAP_TEVII_NEC;
break;
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index ebf448c..f29e18c 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -248,7 +248,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
struct cx88_IR *ir;
struct rc_dev *dev;
char *ir_codes = NULL;
- u64 rc_type = RC_TYPE_OTHER;
+ u64 rc_type = RC_BIT_OTHER;
int err = -ENOMEM;
u32 hardware_mask = 0; /* For devices with a hardware mask, when
* used with a full-code IR table
@@ -416,7 +416,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
break;
case CX88_BOARD_TWINHAN_VP1027_DVBS:
ir_codes = RC_MAP_TWINHAN_VP1027_DVBS;
- rc_type = RC_TYPE_NEC;
+ rc_type = RC_BIT_NEC;
ir->sampling = 0xff00; /* address */
break;
}
@@ -592,7 +592,7 @@ void cx88_i2c_init_ir(struct cx88_core *core)
case CX88_BOARD_LEADTEK_PVR2000:
addr_list = pvr2000_addr_list;
core->init_data.name = "cx88 Leadtek PVR 2000 remote";
- core->init_data.type = RC_TYPE_UNKNOWN;
+ core->init_data.type = RC_BIT_UNKNOWN;
core->init_data.get_key = get_key_pvr2000;
core->init_data.ir_codes = RC_MAP_EMPTY;
break;
@@ -613,7 +613,7 @@ void cx88_i2c_init_ir(struct cx88_core *core)
/* Hauppauge XVR */
core->init_data.name = "cx88 Hauppauge XVR remote";
core->init_data.ir_codes = RC_MAP_HAUPPAUGE;
- core->init_data.type = RC_TYPE_RC5;
+ core->init_data.type = RC_BIT_RC5;
core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
info.platform_data = &core->init_data;
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index fce5f76..55808a9 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -354,14 +354,14 @@ int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
/* Adjust xclk based o IR table for RC5/NEC tables */
- if (rc_type == RC_TYPE_RC5) {
+ if (rc_type == RC_BIT_RC5) {
dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
ir->full_code = 1;
- } else if (rc_type == RC_TYPE_NEC) {
+ } else if (rc_type == RC_BIT_NEC) {
dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
ir_config = EM2874_IR_NEC;
ir->full_code = 1;
- } else if (rc_type != RC_TYPE_UNKNOWN)
+ } else if (rc_type != RC_BIT_UNKNOWN)
rc = -EINVAL;
em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
@@ -544,14 +544,14 @@ static int em28xx_ir_init(struct em28xx *dev)
* em2874 supports more protocols. For now, let's just announce
* the two protocols that were already tested
*/
- rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC;
+ rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC;
rc->priv = ir;
rc->change_protocol = em28xx_ir_change_protocol;
rc->open = em28xx_ir_start;
rc->close = em28xx_ir_stop;
/* By default, keep protocol field untouched */
- err = em28xx_ir_change_protocol(rc, RC_TYPE_UNKNOWN);
+ err = em28xx_ir_change_protocol(rc, RC_BIT_UNKNOWN);
if (err)
goto err_out_free;
diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c
index 82e819f..031cf02 100644
--- a/drivers/media/video/hdpvr/hdpvr-i2c.c
+++ b/drivers/media/video/hdpvr/hdpvr-i2c.c
@@ -55,7 +55,7 @@ struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev)
/* Our default information for ir-kbd-i2c.c to use */
init_data->ir_codes = RC_MAP_HAUPPAUGE;
init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
- init_data->type = RC_TYPE_RC5;
+ init_data->type = RC_BIT_RC5;
init_data->name = "HD-PVR";
init_data->polling_interval = 405; /* ms, duplicated from Windows */
hdpvr_ir_rx_i2c_board_info.platform_data = init_data;
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 04f192a..08ae067 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -284,7 +284,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
char *ir_codes = NULL;
const char *name = NULL;
- u64 rc_type = RC_TYPE_UNKNOWN;
+ u64 rc_type = RC_BIT_UNKNOWN;
struct IR_i2c *ir;
struct rc_dev *rc = NULL;
struct i2c_adapter *adap = client->adapter;
@@ -303,7 +303,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
case 0x64:
name = "Pixelview";
ir->get_key = get_key_pixelview;
- rc_type = RC_TYPE_OTHER;
+ rc_type = RC_BIT_OTHER;
ir_codes = RC_MAP_EMPTY;
break;
case 0x18:
@@ -311,31 +311,31 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
case 0x1a:
name = "Hauppauge";
ir->get_key = get_key_haup;
- rc_type = RC_TYPE_RC5;
+ rc_type = RC_BIT_RC5;
ir_codes = RC_MAP_HAUPPAUGE;
break;
case 0x30:
name = "KNC One";
ir->get_key = get_key_knc1;
- rc_type = RC_TYPE_OTHER;
+ rc_type = RC_BIT_OTHER;
ir_codes = RC_MAP_EMPTY;
break;
case 0x6b:
name = "FusionHDTV";
ir->get_key = get_key_fusionhdtv;
- rc_type = RC_TYPE_RC5;
+ rc_type = RC_BIT_RC5;
ir_codes = RC_MAP_FUSIONHDTV_MCE;
break;
case 0x40:
name = "AVerMedia Cardbus remote";
ir->get_key = get_key_avermedia_cardbus;
- rc_type = RC_TYPE_OTHER;
+ rc_type = RC_BIT_OTHER;
ir_codes = RC_MAP_AVERMEDIA_CARDBUS;
break;
case 0x71:
name = "Hauppauge/Zilog Z8";
ir->get_key = get_key_haup_xvr;
- rc_type = RC_TYPE_RC5;
+ rc_type = RC_BIT_RC5;
ir_codes = RC_MAP_HAUPPAUGE;
break;
}
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index d47f41a..46e262b 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -200,21 +200,21 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
init_data->ir_codes = RC_MAP_AVERMEDIA_CARDBUS;
init_data->internal_get_key_func =
IR_KBD_GET_KEY_AVERMEDIA_CARDBUS;
- init_data->type = RC_TYPE_OTHER;
+ init_data->type = RC_BIT_OTHER;
init_data->name = "AVerMedia AVerTV card";
break;
case IVTV_HW_I2C_IR_RX_HAUP_EXT:
case IVTV_HW_I2C_IR_RX_HAUP_INT:
init_data->ir_codes = RC_MAP_HAUPPAUGE;
init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
- init_data->type = RC_TYPE_RC5;
+ init_data->type = RC_BIT_RC5;
init_data->name = itv->card_name;
break;
case IVTV_HW_Z8F0811_IR_RX_HAUP:
/* Default to grey remote */
init_data->ir_codes = RC_MAP_HAUPPAUGE;
init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
- init_data->type = RC_TYPE_RC5;
+ init_data->type = RC_BIT_RC5;
init_data->name = itv->card_name;
break;
case IVTV_HW_I2C_IR_RX_ADAPTEC:
@@ -222,7 +222,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
init_data->name = itv->card_name;
/* FIXME: The protocol and RC_MAP needs to be corrected */
init_data->ir_codes = RC_MAP_EMPTY;
- init_data->type = RC_TYPE_UNKNOWN;
+ init_data->type = RC_BIT_UNKNOWN;
break;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 885ce11..9ab596c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -581,7 +581,7 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
case PVR2_IR_SCHEME_29XXX: /* Original 29xxx device */
init_data->ir_codes = RC_MAP_HAUPPAUGE;
init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
- init_data->type = RC_TYPE_RC5;
+ init_data->type = RC_BIT_RC5;
init_data->name = hdw->hdw_desc->description;
init_data->polling_interval = 100; /* ms From ir-kbd-i2c */
/* IR Receiver */
@@ -596,7 +596,7 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */
init_data->ir_codes = RC_MAP_HAUPPAUGE;
init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
- init_data->type = RC_TYPE_RC5;
+ init_data->type = RC_BIT_RC5;
init_data->name = hdw->hdw_desc->description;
/* IR Receiver */
info.addr = 0x71;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 05c6e21..6ad49c6 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -995,7 +995,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
dev->init_data.name = "BeholdTV";
dev->init_data.get_key = get_key_beholdm6xx;
dev->init_data.ir_codes = RC_MAP_BEHOLD;
- dev->init_data.type = RC_TYPE_NEC;
+ dev->init_data.type = RC_BIT_NEC;
info.addr = 0x2d;
break;
case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c
index e80b7e1..8ce028f 100644
--- a/drivers/media/video/tm6000/tm6000-input.c
+++ b/drivers/media/video/tm6000/tm6000-input.c
@@ -109,12 +109,12 @@ static int tm6000_ir_config(struct tm6000_IR *ir)
*/
switch (ir->rc_type) {
- case RC_TYPE_NEC:
+ case RC_BIT_NEC:
leader = 900; /* ms */
pulse = 700; /* ms - the actual value would be 562 */
break;
default:
- case RC_TYPE_RC5:
+ case RC_BIT_RC5:
leader = 900; /* ms - from the NEC decoding */
pulse = 1780; /* ms - The actual value would be 1776 */
break;
@@ -122,12 +122,12 @@ static int tm6000_ir_config(struct tm6000_IR *ir)
pulse = ir_clock_mhz * pulse;
leader = ir_clock_mhz * leader;
- if (ir->rc_type == RC_TYPE_NEC)
+ if (ir->rc_type == RC_BIT_NEC)
leader = leader | 0x8000;
- dprintk(2, "%s: %s, %d MHz, leader = 0x%04x, pulse = 0x%06x \n",
+ dprintk(2, "%s: %s, %d MHz, leader = 0x%04x, pulse = 0x%06x\n",
__func__,
- (ir->rc_type == RC_TYPE_NEC) ? "NEC" : "RC-5",
+ (ir->rc_type == RC_BIT_NEC) ? "NEC" : "RC-5",
ir_clock_mhz, leader, pulse);
/* Remote WAKEUP = enable, normal mode, from IR decoder output */
@@ -306,7 +306,7 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
dprintk(2, "%s\n",__func__);
- if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC))
+ if ((rc->rc_map.scan) && (rc_type == RC_BIT_NEC))
ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff);
ir->rc_type = rc_type;
@@ -420,7 +420,7 @@ int tm6000_ir_init(struct tm6000_core *dev)
ir->rc = rc;
/* input setup */
- rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC;
+ rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC;
/* Neded, in order to support NEC remotes with 24 or 32 bits */
rc->scanmask = 0xffff;
rc->priv = ir;
@@ -443,7 +443,7 @@ int tm6000_ir_init(struct tm6000_core *dev)
usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
strlcat(ir->phys, "/input0", sizeof(ir->phys));
- tm6000_ir_change_protocol(rc, RC_TYPE_UNKNOWN);
+ tm6000_ir_change_protocol(rc, RC_BIT_UNKNOWN);
rc->input_name = ir->name;
rc->input_phys = ir->phys;
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
index 768aa77..e221bc7 100644
--- a/include/media/ir-kbd-i2c.h
+++ b/include/media/ir-kbd-i2c.h
@@ -37,7 +37,7 @@ enum ir_kbd_get_key_fn {
struct IR_i2c_init_data {
char *ir_codes;
const char *name;
- u64 type; /* RC_TYPE_RC5, etc */
+ u64 type; /* RC_BIT_RC5, etc */
u32 polling_interval; /* 0 means DEFAULT_POLLING_INTERVAL */
/*
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index b0c494a..58f12da 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -50,7 +50,7 @@ enum rc_driver_type {
* @input_dev: the input child device used to communicate events to userspace
* @driver_type: specifies if protocol decoding is done in hardware or software
* @idle: used to keep track of RX state
- * @allowed_protos: bitmask with the supported RC_TYPE_* protocols
+ * @allowed_protos: bitmask with the supported RC_BIT_* protocols
* @scanmask: some hardware decoders are not capable of providing the full
* scancode to the application. As this is a hardware limit, we can't do
* anything with it. Yet, as the same keycode table can be used with other
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index cfd5163..909c2ed 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -11,22 +11,54 @@
#include <linux/input.h>
-#define RC_TYPE_UNKNOWN 0
-#define RC_TYPE_RC5 (1 << 0) /* Philips RC5 protocol */
-#define RC_TYPE_NEC (1 << 1)
-#define RC_TYPE_RC6 (1 << 2) /* Philips RC6 protocol */
-#define RC_TYPE_JVC (1 << 3) /* JVC protocol */
-#define RC_TYPE_SONY (1 << 4) /* Sony12/15/20 protocol */
-#define RC_TYPE_RC5_SZ (1 << 5) /* RC5 variant used by Streamzap */
-#define RC_TYPE_SANYO (1 << 6) /* Sanyo protocol */
-#define RC_TYPE_MCE_KBD (1 << 29) /* RC6-ish MCE keyboard/mouse */
-#define RC_TYPE_LIRC (1 << 30) /* Pass raw IR to lirc userspace */
-#define RC_TYPE_OTHER (1u << 31)
+enum rc_type {
+ RC_TYPE_UNKNOWN = 0, /* Protocol not known */
+ RC_TYPE_OTHER = 0, /* Protocol known but proprietary */
+ RC_TYPE_LIRC = 1, /* Pass raw IR to lirc userspace */
+ RC_TYPE_RC5 = 2, /* Philips RC5 protocol */
+ RC_TYPE_RC5X = 3, /* Philips RC5x protocol */
+ RC_TYPE_RC5_SZ = 4, /* StreamZap variant of RC5 */
+ RC_TYPE_JVC = 5, /* JVC protocol */
+ RC_TYPE_SONY12 = 6, /* Sony 12 bit protocol */
+ RC_TYPE_SONY15 = 7, /* Sony 15 bit protocol */
+ RC_TYPE_SONY20 = 8, /* Sony 20 bit protocol */
+ RC_TYPE_NEC = 9, /* NEC protocol */
+ RC_TYPE_SANYO = 10, /* Sanyo protocol */
+ RC_TYPE_MCE_KBD = 11, /* RC6-ish MCE keyboard/mouse */
+ RC_TYPE_RC6_0 = 12, /* Philips RC6-0-16 protocol */
+ RC_TYPE_RC6_6A_20 = 13, /* Philips RC6-6A-20 protocol */
+ RC_TYPE_RC6_6A_24 = 14, /* Philips RC6-6A-24 protocol */
+ RC_TYPE_RC6_6A_32 = 15, /* Philips RC6-6A-32 protocol */
+ RC_TYPE_RC6_MCE = 16, /* MCE (Philips RC6-6A-32 subtype) protocol */
+};
+
+#define RC_BIT_NONE 0
+#define RC_BIT_UNKNOWN (1 << RC_TYPE_UNKNOWN)
+#define RC_BIT_OTHER (1 << RC_TYPE_OTHER)
+#define RC_BIT_LIRC (1 << RC_TYPE_LIRC)
+#define RC_BIT_RC5 (1 << RC_TYPE_RC5)
+#define RC_BIT_RC5X (1 << RC_TYPE_RC5X)
+#define RC_BIT_RC5_SZ (1 << RC_TYPE_RC5_SZ)
+#define RC_BIT_JVC (1 << RC_TYPE_JVC)
+#define RC_BIT_SONY12 (1 << RC_TYPE_SONY12)
+#define RC_BIT_SONY15 (1 << RC_TYPE_SONY15)
+#define RC_BIT_SONY20 (1 << RC_TYPE_SONY20)
+#define RC_BIT_NEC (1 << RC_TYPE_NEC)
+#define RC_BIT_SANYO (1 << RC_TYPE_SANYO)
+#define RC_BIT_MCE_KBD (1 << RC_TYPE_MCE_KBD)
+#define RC_BIT_RC6_0 (1 << RC_TYPE_RC6_0)
+#define RC_BIT_RC6_6A_20 (1 << RC_TYPE_RC6_6A_20)
+#define RC_BIT_RC6_6A_24 (1 << RC_TYPE_RC6_6A_24)
+#define RC_BIT_RC6_6A_32 (1 << RC_TYPE_RC6_6A_32)
+#define RC_BIT_RC6_MCE (1 << RC_TYPE_RC6_MCE)
-#define RC_TYPE_ALL (RC_TYPE_RC5 | RC_TYPE_NEC | RC_TYPE_RC6 | \
- RC_TYPE_JVC | RC_TYPE_SONY | RC_TYPE_LIRC | \
- RC_TYPE_RC5_SZ | RC_TYPE_SANYO | RC_TYPE_MCE_KBD | \
- RC_TYPE_OTHER)
+#define RC_BIT_ALL (RC_BIT_UNKNOWN | RC_BIT_OTHER | RC_BIT_LIRC | \
+ RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \
+ RC_BIT_JVC | \
+ RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \
+ RC_BIT_NEC | RC_BIT_SANYO | RC_BIT_MCE_KBD | \
+ RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
+ RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE)
struct rc_map_table {
u32 scancode;
@@ -38,7 +70,7 @@ struct rc_map {
unsigned int size; /* Max number of entries */
unsigned int len; /* Used number of entries */
unsigned int alloc; /* Size of *scan in bytes */
- u64 rc_type;
+ enum rc_type rc_type;
const char *name;
spinlock_t lock;
};
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 03/43] rc-core: don't throw away protocol information
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
2012-05-23 9:42 ` [PATCH 01/43] rc-core: move timeout and checks to lirc David Härdeman
2012-05-23 9:42 ` [PATCH 02/43] rc-core: add separate defines for protocol bitmaps and numbers David Härdeman
@ 2012-05-23 9:42 ` David Härdeman
2012-05-23 9:42 ` [PATCH 04/43] rc-core: use the full 32 bits for NEC scancodes David Härdeman
` (40 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:42 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Setting and getting keycodes in the input subsystem used to be done via
the EVIOC[GS]KEYCODE ioctl and "unsigned int[2]" (one int for scancode
and one for the keycode).
The interface has now been extended to use the EVIOC[GS]KEYCODE_V2 ioctl
which uses the following struct:
struct input_keymap_entry {
__u8 flags;
__u8 len;
__u16 index;
__u32 keycode;
__u8 scancode[32];
};
(scancode can of course be even bigger, thanks to the len member).
This patch changes how the "input_keymap_entry" struct is interpreted
by rc-core by casting it to "rc_keymap_entry":
struct rc_scancode {
__u16 protocol;
__u16 reserved[3];
__u64 scancode;
}
struct rc_keymap_entry {
__u8 flags;
__u8 len;
__u16 index;
__u32 keycode;
union {
struct rc_scancode rc;
__u8 raw[32];
};
};
The u64 scancode member is large enough for all current protocols and it
would be possible to extend it in the future should it be necessary for
some exotic protocol.
The main advantage with this change is that the protocol is made explicit,
which means that we're not throwing away data (the protocol type) and that
it'll be easier to support multiple protocols with one decoder (think rc5
and rc5-streamzap).
Further patches will also add the ability to communicate the protocol to
userspace.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/dvb/dm1105/dm1105.c | 3
drivers/media/dvb/dvb-usb/af9015.c | 4
drivers/media/dvb/dvb-usb/af9035.c | 2
drivers/media/dvb/dvb-usb/anysee.c | 2
drivers/media/dvb/dvb-usb/az6007.c | 25 ++-
drivers/media/dvb/dvb-usb/dib0700_core.c | 2
drivers/media/dvb/dvb-usb/dib0700_devices.c | 10 +
drivers/media/dvb/dvb-usb/dvb-usb.h | 2
drivers/media/dvb/dvb-usb/it913x.c | 19 +-
drivers/media/dvb/dvb-usb/lmedm04.c | 3
drivers/media/dvb/dvb-usb/pctv452e.c | 11 +
drivers/media/dvb/dvb-usb/rtl28xxu.c | 17 +-
drivers/media/dvb/dvb-usb/ttusb2.c | 2
drivers/media/dvb/ttpci/budget-ci.c | 7 -
drivers/media/rc/ati_remote.c | 13 +
drivers/media/rc/imon.c | 10 +
drivers/media/rc/ir-jvc-decoder.c | 4
drivers/media/rc/ir-lirc-codec.c | 2
drivers/media/rc/ir-mce_kbd-decoder.c | 2
drivers/media/rc/ir-nec-decoder.c | 4
drivers/media/rc/ir-raw.c | 2
drivers/media/rc/ir-rc5-decoder.c | 23 +--
drivers/media/rc/ir-rc5-sz-decoder.c | 4
drivers/media/rc/ir-rc6-decoder.c | 48 +++---
drivers/media/rc/ir-sanyo-decoder.c | 4
drivers/media/rc/ir-sony-decoder.c | 26 +--
drivers/media/rc/rc-core-priv.h | 1
drivers/media/rc/rc-main.c | 235 +++++++++++++++++++--------
drivers/media/video/bt8xx/bttv-input.c | 15 +-
drivers/media/video/cx88/cx88-input.c | 10 +
drivers/media/video/em28xx/em28xx-cards.c | 15 ++
drivers/media/video/em28xx/em28xx-input.c | 34 ++--
drivers/media/video/em28xx/em28xx.h | 1
drivers/media/video/ir-kbd-i2c.c | 12 +
drivers/media/video/saa7134/saa7134-input.c | 6 -
drivers/media/video/tm6000/tm6000-cards.c | 2
drivers/media/video/tm6000/tm6000-input.c | 61 ++++---
include/media/rc-core.h | 28 +++
include/media/rc-map.h | 17 ++
39 files changed, 434 insertions(+), 254 deletions(-)
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index a609b3a..04a02ba 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -677,7 +677,8 @@ static void dm1105_emit_key(struct work_struct *work)
data = (ircom >> 8) & 0x7f;
- rc_keydown(ir->dev, data, 0);
+ /* Yes, UNKNOWN because we don't generate a full NEC scancode (yet?) */
+ rc_keydown(ir->dev, RC_TYPE_UNKNOWN, data, 0);
}
/* work handler */
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 5395c6a..bd47e68 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -1046,7 +1046,7 @@ static int af9015_rc_query(struct dvb_usb_device *d)
if ((priv->rc_repeat != buf[6] || buf[0]) &&
!memcmp(&buf[12], priv->rc_last, 4)) {
deb_rc("%s: key repeated\n", __func__);
- rc_keydown(d->rc_dev, priv->rc_keycode, 0);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC, priv->rc_keycode, 0);
priv->rc_repeat = buf[6];
return ret;
}
@@ -1077,7 +1077,7 @@ static int af9015_rc_query(struct dvb_usb_device *d)
priv->rc_keycode = buf[12] << 24 | buf[13] << 16 |
buf[14] << 8 | buf[15];
}
- rc_keydown(d->rc_dev, priv->rc_keycode, 0);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC, priv->rc_keycode, 0);
} else {
deb_rc("%s: no key press\n", __func__);
/* Invalidate last keypress */
diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c
index d7c7c17..c000feb 100644
--- a/drivers/media/dvb/dvb-usb/af9035.c
+++ b/drivers/media/dvb/dvb-usb/af9035.c
@@ -325,7 +325,7 @@ static int af9035_rc_query(struct dvb_usb_device *d)
key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
}
- rc_keydown(d->rc_dev, key, 0);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC, key, 0);
err:
/* ignore errors */
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index f510f91..6053670 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -1058,7 +1058,7 @@ static int anysee_rc_query(struct dvb_usb_device *d)
if (ircode[0]) {
deb_rc("%s: key pressed %02x\n", __func__, ircode[1]);
- rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0);
+ rc_keydown(d->rc_dev, RC_TYPE_OTHER, 0x08 << 8 | ircode[1], 0);
}
return 0;
diff --git a/drivers/media/dvb/dvb-usb/az6007.c b/drivers/media/dvb/dvb-usb/az6007.c
index 102114e..1e26863 100644
--- a/drivers/media/dvb/dvb-usb/az6007.c
+++ b/drivers/media/dvb/dvb-usb/az6007.c
@@ -197,24 +197,27 @@ static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
static int az6007_rc_query(struct dvb_usb_device *d)
{
struct az6007_device_state *st = d->priv;
- unsigned code = 0;
+ u64 code;
az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10);
if (st->data[1] == 0x44)
return 0;
- if ((st->data[1] ^ st->data[2]) == 0xff)
- code = st->data[1];
- else
- code = st->data[1] << 8 | st->data[2];
-
- if ((st->data[3] ^ st->data[4]) == 0xff)
- code = code << 8 | st->data[3];
- else
- code = code << 16 | st->data[3] << 8 | st->data[4];
+ if ((st->data[3] ^ st->data[4]) == 0xff) {
+ if ((st->data[1] ^ st->data[2]) == 0xff)
+ code = RC_SCANCODE_NEC(st->data[1], st->data[3]);
+ else
+ code = RC_SCANCODE_NECX(st->data[1] << 8 | st->data[2],
+ st->data[3]);
+ } else {
+ code = RC_SCANCODE_NEC32(st->data[1] << 24 |
+ st->data[2] << 16 |
+ st->data[3] << 8 |
+ st->data[4]);
+ }
- rc_keydown(d->rc_dev, code, st->data[5]);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC, code, st->data[5]);
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 192d805..f57c3f8 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -744,7 +744,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
goto resubmit;
}
- rc_keydown(d->rc_dev, keycode, toggle);
+ rc_keydown(d->rc_dev, d->props.rc.core.protocol, keycode, toggle);
resubmit:
/* Clean the buffer before we requeue */
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 1179842..b1b94f7 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -489,7 +489,7 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
{
u8 key[4];
- u32 keycode;
+ u64 keycode;
u8 toggle;
int i;
struct dib0700_state *st = d->priv;
@@ -524,17 +524,17 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
(key[3] == 0xff))
keycode = d->last_event;
else {
- keycode = key[3-2] << 8 | key[3-3];
+ keycode = RC_SCANCODE_NEC(key[3-2], key[3-3]);
d->last_event = keycode;
}
- rc_keydown(d->rc_dev, keycode, 0);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC, keycode, 0);
break;
default:
/* RC-5 protocol changes toggle bit on new keypress */
- keycode = key[3-2] << 8 | key[3-3];
+ keycode = RC_SCANCODE_RC5(key[3-2], key[3-3]);
toggle = key[3-1];
- rc_keydown(d->rc_dev, keycode, toggle);
+ rc_keydown(d->rc_dev, RC_TYPE_RC5, keycode, toggle);
break;
}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index 99f9440..ed886ae 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -449,7 +449,7 @@ struct dvb_usb_device {
struct input_dev *input_dev;
char rc_phys[64];
struct delayed_work rc_query_work;
- u32 last_event;
+ u64 last_event;
int last_state;
struct module *owner;
diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c
index e54f3dc..2c3c400 100644
--- a/drivers/media/dvb/dvb-usb/it913x.c
+++ b/drivers/media/dvb/dvb-usb/it913x.c
@@ -381,7 +381,12 @@ static int it913x_rc_query(struct dvb_usb_device *d)
{
u8 ibuf[4];
int ret;
- u32 key;
+ u16 device, command;
+ u64 scancode;
+
+ if (!d->rc_dev)
+ return 0;
+
/* Avoid conflict with frontends*/
mutex_lock(&d->i2c_mutex);
@@ -389,12 +394,12 @@ static int it913x_rc_query(struct dvb_usb_device *d)
0, 0, &ibuf[0], sizeof(ibuf));
if ((ibuf[2] + ibuf[3]) == 0xff) {
- key = ibuf[2];
- key += ibuf[0] << 16;
- key += ibuf[1] << 8;
- deb_info(1, "NEC Extended Key =%08x", key);
- if (d->rc_dev != NULL)
- rc_keydown(d->rc_dev, key, 0);
+ command = ibuf[2];
+ device = (ibuf[0] << 8) | ibuf[1];
+ scancode = RC_SCANCODE_NECX(device, command);
+ deb_info(1, "NEC Extended Key = 0x%08llx",
+ (unsigned long long)scancode);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC, scancode, 0);
}
mutex_unlock(&d->i2c_mutex);
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c
index 8ff161e..4280e07 100644
--- a/drivers/media/dvb/dvb-usb/lmedm04.c
+++ b/drivers/media/dvb/dvb-usb/lmedm04.c
@@ -284,7 +284,8 @@ static void lme2510_int_response(struct urb *lme_urb)
key += (ibuf[2] ^ 0xff) << 16;
deb_info(1, "INT Key =%08x", key);
if (adap->dev->rc_dev != NULL)
- rc_keydown(adap->dev->rc_dev, key, 0);
+ rc_keydown(adap->dev->rc_dev,
+ RC_TYPE_UNKNOWN, key, 0);
}
break;
case 0xbb:
diff --git a/drivers/media/dvb/dvb-usb/pctv452e.c b/drivers/media/dvb/dvb-usb/pctv452e.c
index 6eefd4e..a64fa5d 100644
--- a/drivers/media/dvb/dvb-usb/pctv452e.c
+++ b/drivers/media/dvb/dvb-usb/pctv452e.c
@@ -96,7 +96,7 @@ struct pctv452e_state {
u8 c; /* transaction counter, wraps around... */
u8 initialized; /* set to 1 if 0x15 has been sent */
- u16 last_rc_key;
+ u64 last_scancode;
};
static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data,
@@ -566,15 +566,14 @@ static int pctv452e_rc_query(struct dvb_usb_device *d)
if ((rx[3] == 9) && (rx[12] & 0x01)) {
/* got a "press" event */
- state->last_rc_key = (rx[7] << 8) | rx[6];
+ state->last_scancode = RC_SCANCODE_RC5(rx[7], rx[6]);
if (debug > 2)
info("%s: cmd=0x%02x sys=0x%02x\n",
__func__, rx[6], rx[7]);
-
- rc_keydown(d->rc_dev, state->last_rc_key, 0);
- } else if (state->last_rc_key) {
+ rc_keydown(d->rc_dev, RC_TYPE_RC5, state->last_scancode, 0);
+ } else if (state->last_scancode) {
rc_keyup(d->rc_dev);
- state->last_rc_key = 0;
+ state->last_scancode = 0;
}
return 0;
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c
index 1abd247..b2749d8 100644
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.c
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c
@@ -639,7 +639,7 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
int ret, i;
struct rtl28xxu_priv *priv = d->priv;
u8 buf[5];
- u32 rc_code;
+ u64 rc_code;
struct rtl28xxu_reg_val rc_nec_tab[] = {
{ 0x3033, 0x80 },
{ 0x3020, 0x43 },
@@ -676,19 +676,22 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
if (buf[2] == (u8) ~buf[3]) {
if (buf[0] == (u8) ~buf[1]) {
/* NEC standard (16 bit) */
- rc_code = buf[0] << 8 | buf[2];
+ rc_code = RC_SCANCODE_NEC(buf[0], buf[2]);
} else {
/* NEC extended (24 bit) */
- rc_code = buf[0] << 16 |
- buf[1] << 8 | buf[2];
+ rc_code = RC_SCANCODE_NECX(buf[0] << 8 |
+ buf[1],
+ buf[2]);
}
} else {
/* NEC full (32 bit) */
- rc_code = buf[0] << 24 | buf[1] << 16 |
- buf[2] << 8 | buf[3];
+ rc_code = RC_SCANCODE_NEC32(buf[0] << 24 |
+ buf[1] << 16 |
+ buf[2] << 8 |
+ buf[3]);
}
- rc_keydown(d->rc_dev, rc_code, 0);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC, rc_code, 0);
ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1);
if (ret)
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c
index c5be462..ad57689 100644
--- a/drivers/media/dvb/dvb-usb/ttusb2.c
+++ b/drivers/media/dvb/dvb-usb/ttusb2.c
@@ -440,7 +440,7 @@ static int tt3650_rc_query(struct dvb_usb_device *d)
/* got a "press" event */
st->last_rc_key = (rx[3] << 8) | rx[2];
deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]);
- rc_keydown(d->rc_dev, st->last_rc_key, 0);
+ rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN, st->last_rc_key, 0);
} else if (st->last_rc_key) {
rc_keyup(d->rc_dev);
st->last_rc_key = 0;
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 98e5241..2ee6b57 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -161,14 +161,15 @@ static void msp430_ir_interrupt(unsigned long data)
return;
if (budget_ci->ir.full_rc5) {
- rc_keydown(dev,
- budget_ci->ir.rc5_device <<8 | budget_ci->ir.ir_key,
+ rc_keydown(dev, RC_TYPE_RC5,
+ RC_SCANCODE_RC5(budget_ci->ir.rc5_device,
+ budget_ci->ir.ir_key),
(command & 0x20) ? 1 : 0);
return;
}
/* FIXME: We should generate complete scancodes for all devices */
- rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0);
+ rc_keydown(dev, RC_TYPE_UNKNOWN, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0);
}
static int msp430_ir_init(struct budget_ci *budget_ci)
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index dfeabd7..229f742 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -541,6 +541,7 @@ static void ati_remote_input_report(struct urb *urb)
* set, assume this is a scrollwheel up/down event.
*/
wheel_keycode = rc_g_keycode_from_table(ati_remote->rdev,
+ RC_TYPE_OTHER,
scancode & 0x78);
if (wheel_keycode == KEY_RESERVED) {
@@ -609,12 +610,12 @@ static void ati_remote_input_report(struct urb *urb)
while (count--) {
/*
- * We don't use the rc-core repeat handling yet as
- * it would cause ghost repeats which would be a
- * regression for this driver.
- */
- rc_keydown_notimeout(ati_remote->rdev, scancode,
- data[2]);
+ * We don't use the rc-core repeat handling yet as
+ * it would cause ghost repeats which would be a
+ * regression for this driver.
+ */
+ rc_keydown_notimeout(ati_remote->rdev, RC_TYPE_OTHER,
+ scancode, data[2]);
rc_keyup(ati_remote->rdev);
}
return;
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 24eb493..d98778b 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -1162,14 +1162,15 @@ static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 scancode)
bool is_release_code = false;
/* Look for the initial press of a button */
- keycode = rc_g_keycode_from_table(ictx->rdev, scancode);
+ keycode = rc_g_keycode_from_table(ictx->rdev, ictx->rc_type, scancode);
ictx->rc_toggle = 0x0;
ictx->rc_scancode = scancode;
/* Look for the release of a button */
if (keycode == KEY_RESERVED) {
release = scancode & ~0x4000;
- keycode = rc_g_keycode_from_table(ictx->rdev, release);
+ keycode = rc_g_keycode_from_table(ictx->rdev, ictx->rc_type,
+ release);
if (keycode != KEY_RESERVED)
is_release_code = true;
}
@@ -1198,7 +1199,7 @@ static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode)
scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT;
ictx->rc_scancode = scancode;
- keycode = rc_g_keycode_from_table(ictx->rdev, scancode);
+ keycode = rc_g_keycode_from_table(ictx->rdev, ictx->rc_type, scancode);
/* not used in mce mode, but make sure we know its false */
ictx->release_code = false;
@@ -1580,7 +1581,8 @@ static void imon_incoming_packet(struct imon_context *ictx,
if (press_type == 0)
rc_keyup(ictx->rdev);
else {
- rc_keydown(ictx->rdev, ictx->rc_scancode, ictx->rc_toggle);
+ rc_keydown(ictx->rdev, ictx->rc_type,
+ ictx->rc_scancode, ictx->rc_toggle);
spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->last_keycode = ictx->kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 69edffb..30bcf18 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -47,7 +47,7 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
struct jvc_dec *data = &dev->raw->jvc;
- if (!(dev->raw->enabled_protocols & RC_BIT_JVC))
+ if (!(dev->enabled_protocols & RC_BIT_JVC))
return 0;
if (!is_timing_event(ev)) {
@@ -140,7 +140,7 @@ again:
scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
(bitrev8((data->bits >> 0) & 0xff) << 0);
IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
- rc_keydown(dev, scancode, data->toggle);
+ rc_keydown(dev, RC_TYPE_JVC, scancode, data->toggle);
data->first = false;
data->old_bits = data->bits;
} else if (data->bits == data->old_bits) {
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 439879c..1490a8b 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -35,7 +35,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
struct lirc_codec *lirc = &dev->raw->lirc;
int sample;
- if (!(dev->raw->enabled_protocols & RC_BIT_LIRC))
+ if (!(dev->enabled_protocols & RC_BIT_LIRC))
return 0;
if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf)
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 33fafa4..9f3c9b5 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -216,7 +216,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
unsigned long delay;
- if (!(dev->raw->enabled_protocols & RC_BIT_MCE_KBD))
+ if (!(dev->enabled_protocols & RC_BIT_MCE_KBD))
return 0;
if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index dc21a67..535e6e2 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -52,7 +52,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 address, not_address, command, not_command;
bool send_32bits = false;
- if (!(dev->raw->enabled_protocols & RC_BIT_NEC))
+ if (!(dev->enabled_protocols & RC_BIT_NEC))
return 0;
if (!is_timing_event(ev)) {
@@ -189,7 +189,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (data->is_nec_x)
data->necx_repeat = true;
- rc_keydown(dev, scancode, 0);
+ rc_keydown(dev, RC_TYPE_NEC, scancode, 0);
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index a820251..6b3c9e5 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -259,7 +259,7 @@ int ir_raw_event_register(struct rc_dev *dev)
return -ENOMEM;
dev->raw->dev = dev;
- dev->raw->enabled_protocols = ~0;
+ dev->enabled_protocols = ~0;
rc = kfifo_alloc(&dev->raw->kfifo,
sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
GFP_KERNEL);
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 5b4d1dd..ddbf9bf 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -51,8 +51,9 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
struct rc5_dec *data = &dev->raw->rc5;
u8 toggle;
u32 scancode;
+ enum rc_type protocol;
- if (!(dev->raw->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X)))
+ if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X)))
return 0;
if (!is_timing_event(ev)) {
@@ -128,38 +129,30 @@ again:
if (data->wanted_bits == RC5X_NBITS) {
/* RC5X */
u8 xdata, command, system;
- if (!(dev->raw->enabled_protocols & RC_BIT_RC5X)) {
- data->state = STATE_INACTIVE;
- return 0;
- }
xdata = (data->bits & 0x0003F) >> 0;
command = (data->bits & 0x00FC0) >> 6;
system = (data->bits & 0x1F000) >> 12;
toggle = (data->bits & 0x20000) ? 1 : 0;
command += (data->bits & 0x01000) ? 0 : 0x40;
scancode = system << 16 | command << 8 | xdata;
-
- IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
- scancode, toggle);
-
+ protocol = RC_TYPE_RC5X;
} else {
/* RC5 */
u8 command, system;
- if (!(dev->raw->enabled_protocols & RC_BIT_RC5)) {
- data->state = STATE_INACTIVE;
- return 0;
- }
command = (data->bits & 0x0003F) >> 0;
system = (data->bits & 0x007C0) >> 6;
toggle = (data->bits & 0x00800) ? 1 : 0;
command += (data->bits & 0x01000) ? 0 : 0x40;
scancode = system << 8 | command;
+ protocol = RC_TYPE_RC5;
+ }
- IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
+ if (dev->enabled_protocols & (1 << protocol)) {
+ IR_dprintk(1, "RC5(x) scancode 0x%06x (toggle: %u)\n",
scancode, toggle);
+ rc_keydown(dev, protocol, scancode, toggle);
}
- rc_keydown(dev, scancode, toggle);
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c
index fd807a8..8681b96 100644
--- a/drivers/media/rc/ir-rc5-sz-decoder.c
+++ b/drivers/media/rc/ir-rc5-sz-decoder.c
@@ -48,7 +48,7 @@ static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 toggle, command, system;
u32 scancode;
- if (!(dev->raw->enabled_protocols & RC_BIT_RC5_SZ))
+ if (!(dev->enabled_protocols & RC_BIT_RC5_SZ))
return 0;
if (!is_timing_event(ev)) {
@@ -115,7 +115,7 @@ again:
IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n",
scancode, toggle);
- rc_keydown(dev, scancode, toggle);
+ rc_keydown(dev, RC_TYPE_RC5_SZ, scancode, toggle);
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index e19072f..571107e 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -88,8 +88,9 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
struct rc6_dec *data = &dev->raw->rc6;
u32 scancode;
u8 toggle;
+ enum rc_type protocol;
- if (!(dev->raw->enabled_protocols &
+ if (!(dev->enabled_protocols &
(RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 |
RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE)))
return 0;
@@ -231,36 +232,45 @@ again:
switch (rc6_mode(data)) {
case RC6_MODE_0:
+ protocol = RC_TYPE_RC6_0;
scancode = data->body;
toggle = data->toggle;
- IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
- scancode, toggle);
break;
- case RC6_MODE_6A:
- if (data->count > CHAR_BIT * sizeof data->body) {
- IR_dprintk(1, "RC6 too many (%u) data bits\n",
- data->count);
- goto out;
- }
+ case RC6_MODE_6A:
scancode = data->body;
- if (data->count == RC6_6A_32_NBITS &&
- (scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
- /* MCE RC */
- toggle = (scancode & RC6_6A_MCE_TOGGLE_MASK) ? 1 : 0;
- scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
- } else {
- toggle = 0;
+ toggle = 0;
+ switch (data->count) {
+ case 20:
+ protocol = RC_TYPE_RC6_6A_20;
+ break;
+ case 24:
+ protocol = RC_TYPE_RC6_6A_24;
+ break;
+ case 32:
+ protocol = RC_TYPE_RC6_6A_32;
+ if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
+ /* MCE RC */
+ toggle = (scancode & RC6_6A_MCE_TOGGLE_MASK) ? 1 : 0;
+ scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
+ protocol = RC_TYPE_RC6_MCE;
+ }
+ break;
+ default:
+ IR_dprintk(1, "RC6 invalid number of data bits (%u)\n",
+ data->count);
+ goto out;
}
- IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n",
- scancode, toggle);
break;
+
default:
IR_dprintk(1, "RC6 unknown mode\n");
goto out;
}
- rc_keydown(dev, scancode, toggle);
+ IR_dprintk(1, "RC6(%u), scancode 0x%08x (toggle: %u)\n",
+ protocol, scancode, toggle);
+ rc_keydown(dev, protocol, scancode, toggle);
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index 7e69a3b..a95c869 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -58,7 +58,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
u8 address, command, not_command;
- if (!(dev->raw->enabled_protocols & RC_BIT_SANYO))
+ if (!(dev->enabled_protocols & RC_BIT_SANYO))
return 0;
if (!is_timing_event(ev)) {
@@ -167,7 +167,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
scancode = address << 8 | command;
IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode);
- rc_keydown(dev, scancode, 0);
+ rc_keydown(dev, RC_TYPE_SANYO, scancode, 0);
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index fb91434..f360e40 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -44,8 +44,9 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
struct sony_dec *data = &dev->raw->sony;
u32 scancode;
u8 device, subdevice, function;
+ enum rc_type protocol;
- if (!(dev->raw->enabled_protocols &
+ if (!(dev->enabled_protocols &
(RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20)))
return 0;
@@ -124,40 +125,33 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
switch (data->count) {
case 12:
- if (!(dev->raw->enabled_protocols & RC_BIT_SONY12)) {
- data->state = STATE_INACTIVE;
- return 0;
- }
device = bitrev8((data->bits << 3) & 0xF8);
subdevice = 0;
function = bitrev8((data->bits >> 4) & 0xFE);
+ protocol = RC_TYPE_SONY12;
break;
case 15:
- if (!(dev->raw->enabled_protocols & RC_BIT_SONY15)) {
- data->state = STATE_INACTIVE;
- return 0;
- }
device = bitrev8((data->bits >> 0) & 0xFF);
subdevice = 0;
function = bitrev8((data->bits >> 7) & 0xFE);
+ protocol = RC_TYPE_SONY15;
break;
case 20:
- if (!(dev->raw->enabled_protocols & RC_BIT_SONY20)) {
- data->state = STATE_INACTIVE;
- return 0;
- }
device = bitrev8((data->bits >> 5) & 0xF8);
subdevice = bitrev8((data->bits >> 0) & 0xFF);
function = bitrev8((data->bits >> 12) & 0xFE);
+ protocol = RC_TYPE_SONY20;
break;
default:
IR_dprintk(1, "Sony invalid bitcount %u\n", data->count);
goto out;
}
- scancode = device << 16 | subdevice << 8 | function;
- IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode);
- rc_keydown(dev, scancode, 0);
+ if (dev->enabled_protocols & (1 << protocol)) {
+ scancode = device << 16 | subdevice << 8 | function;
+ IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode);
+ rc_keydown(dev, protocol, scancode, 0);
+ }
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 96f0a8b..4de2d47 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -39,7 +39,6 @@ struct ir_raw_event_ctrl {
ktime_t last_event; /* when last event occurred */
enum raw_event_type last_type; /* last event type */
struct rc_dev *dev; /* pointer to the parent rc_dev */
- u64 enabled_protocols; /* enabled raw protocol decoders */
/* raw decoder state follows */
struct ir_raw_event prev_ev;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 3455a9e..4adaa87 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -96,7 +96,7 @@ EXPORT_SYMBOL_GPL(rc_map_unregister);
static struct rc_map_table empty[] = {
- { 0x2a, KEY_COFFEE },
+ { RC_TYPE_OTHER, 0x2a, KEY_COFFEE },
};
static struct rc_map_list empty_map = {
@@ -112,7 +112,6 @@ static struct rc_map_list empty_map = {
* ir_create_table() - initializes a scancode table
* @rc_map: the rc_map to initialize
* @name: name to assign to the table
- * @rc_type: ir type to assign to the new table
* @size: initial size of the table
* @return: zero on success or a negative error code
*
@@ -120,10 +119,9 @@ static struct rc_map_list empty_map = {
* memory to hold at least the specified number of elements.
*/
static int ir_create_table(struct rc_map *rc_map,
- const char *name, u64 rc_type, size_t size)
+ const char *name, size_t size)
{
rc_map->name = name;
- rc_map->rc_type = rc_type;
rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
@@ -218,16 +216,20 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
/* Did the user wish to remove the mapping? */
if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
- IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
- index, rc_map->scan[index].scancode);
+ IR_dprintk(1, "#%d: Deleting proto 0x%04x, scan 0x%08llx\n",
+ index, rc_map->scan[index].protocol,
+ (unsigned long long)rc_map->scan[index].scancode);
rc_map->len--;
memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
(rc_map->len - index) * sizeof(struct rc_map_table));
} else {
- IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n",
+ IR_dprintk(1, "#%d: %s proto 0x%04x, scan 0x%08llx "
+ "with key 0x%04x\n",
index,
old_keycode == KEY_RESERVED ? "New" : "Replacing",
- rc_map->scan[index].scancode, new_keycode);
+ rc_map->scan[index].protocol,
+ (unsigned long long)rc_map->scan[index].scancode,
+ new_keycode);
rc_map->scan[index].keycode = new_keycode;
__set_bit(new_keycode, dev->input_dev->keybit);
}
@@ -254,9 +256,9 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
* ir_establish_scancode() - set a keycode in the scancode->keycode table
* @dev: the struct rc_dev device descriptor
* @rc_map: scancode table to be searched
- * @scancode: the desired scancode
- * @resize: controls whether we allowed to resize the table to
- * accommodate not yet present scancodes
+ * @entry: the entry to be added to the table
+ * @resize: controls whether we are allowed to resize the table to
+ * accomodate not yet present scancodes
* @return: index of the mapping containing scancode in question
* or -1U in case of failure.
*
@@ -266,7 +268,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
*/
static unsigned int ir_establish_scancode(struct rc_dev *dev,
struct rc_map *rc_map,
- unsigned int scancode,
+ struct rc_map_table *entry,
bool resize)
{
unsigned int i;
@@ -280,16 +282,27 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev,
* indicate the valid bits of the scancodes.
*/
if (dev->scanmask)
- scancode &= dev->scanmask;
+ entry->scancode &= dev->scanmask;
- /* First check if we already have a mapping for this ir command */
+ /*
+ * First check if we already have a mapping for this command.
+ * Note that the keytable is sorted first on protocol and second
+ * on scancode (lowest to highest).
+ */
for (i = 0; i < rc_map->len; i++) {
- if (rc_map->scan[i].scancode == scancode)
- return i;
+ if (rc_map->scan[i].protocol < entry->protocol)
+ continue;
- /* Keytable is sorted from lowest to highest scancode */
- if (rc_map->scan[i].scancode >= scancode)
+ if (rc_map->scan[i].protocol > entry->protocol)
break;
+
+ if (rc_map->scan[i].scancode < entry->scancode)
+ continue;
+
+ if (rc_map->scan[i].scancode > entry->scancode)
+ break;
+
+ return i;
}
/* No previous mapping found, we might need to grow the table */
@@ -302,7 +315,8 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev,
if (i < rc_map->len)
memmove(&rc_map->scan[i + 1], &rc_map->scan[i],
(rc_map->len - i) * sizeof(struct rc_map_table));
- rc_map->scan[i].scancode = scancode;
+ rc_map->scan[i].scancode = entry->scancode;
+ rc_map->scan[i].protocol = entry->protocol;
rc_map->scan[i].keycode = KEY_RESERVED;
rc_map->len++;
@@ -325,10 +339,12 @@ static int ir_setkeycode(struct input_dev *idev,
struct rc_dev *rdev = input_get_drvdata(idev);
struct rc_map *rc_map = &rdev->rc_map;
unsigned int index;
- unsigned int scancode;
+ struct rc_map_table entry;
int retval = 0;
unsigned long flags;
+ entry.keycode = ke->keycode;
+
spin_lock_irqsave(&rc_map->lock, flags);
if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
@@ -337,19 +353,52 @@ static int ir_setkeycode(struct input_dev *idev,
retval = -EINVAL;
goto out;
}
- } else {
+ } else if (ke->len == sizeof(int)) {
+ /* Legacy EVIOCSKEYCODE ioctl */
+ u32 scancode;
retval = input_scancode_to_scalar(ke, &scancode);
if (retval)
goto out;
+ entry.scancode = scancode;
+
+ /* Some heuristics to guess the correct protocol */
+ if (hweight64(rdev->enabled_protocols) == 1)
+ entry.protocol = rdev->enabled_protocols;
+ else if (hweight64(rdev->allowed_protos) == 1)
+ entry.protocol = rdev->allowed_protos;
+ else if (rc_map->len > 0)
+ entry.protocol = rc_map->scan[0].protocol;
+ else
+ entry.protocol = RC_TYPE_OTHER;
+
+ index = ir_establish_scancode(rdev, rc_map, &entry, true);
+ if (index >= rc_map->len) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ } else if (ke->len == sizeof(struct rc_scancode)) {
+ /* New EVIOCSKEYCODE_V2 ioctl */
+ const struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
+ entry.protocol = rke->rc.protocol;
+ entry.scancode = rke->rc.scancode;
- index = ir_establish_scancode(rdev, rc_map, scancode, true);
+ if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[1]) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ index = ir_establish_scancode(rdev, rc_map, &entry, true);
if (index >= rc_map->len) {
retval = -ENOMEM;
goto out;
}
+ } else {
+ retval = -EINVAL;
+ goto out;
}
- *old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode);
+ if (retval == 0)
+ *old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode);
out:
spin_unlock_irqrestore(&rc_map->lock, flags);
@@ -369,11 +418,11 @@ static int ir_setkeytable(struct rc_dev *dev,
const struct rc_map *from)
{
struct rc_map *rc_map = &dev->rc_map;
+ struct rc_map_table entry;
unsigned int i, index;
int rc;
- rc = ir_create_table(rc_map, from->name,
- from->rc_type, from->size);
+ rc = ir_create_table(rc_map, from->name, from->size);
if (rc)
return rc;
@@ -381,15 +430,15 @@ static int ir_setkeytable(struct rc_dev *dev,
rc_map->size, rc_map->alloc);
for (i = 0; i < from->size; i++) {
- index = ir_establish_scancode(dev, rc_map,
- from->scan[i].scancode, false);
+ entry.protocol = from->scan[i].protocol;
+ entry.scancode = from->scan[i].scancode;
+ index = ir_establish_scancode(dev, rc_map, &entry, false);
if (index >= rc_map->len) {
rc = -ENOMEM;
break;
}
- ir_update_mapping(dev, rc_map, index,
- from->scan[i].keycode);
+ ir_update_mapping(dev, rc_map, index, from->scan[i].keycode);
}
if (rc)
@@ -401,6 +450,7 @@ static int ir_setkeytable(struct rc_dev *dev,
/**
* ir_lookup_by_scancode() - locate mapping by scancode
* @rc_map: the struct rc_map to search
+ * @protocol: protocol to look for in the table
* @scancode: scancode to look for in the table
* @return: index in the table, -1U if not found
*
@@ -408,17 +458,24 @@ static int ir_setkeytable(struct rc_dev *dev,
* given scancode.
*/
static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
- unsigned int scancode)
+ u16 protocol, u64 scancode)
{
int start = 0;
int end = rc_map->len - 1;
int mid;
+ struct rc_map_table *m;
while (start <= end) {
mid = (start + end) / 2;
- if (rc_map->scan[mid].scancode < scancode)
+ m = &rc_map->scan[mid];
+
+ if (m->protocol < protocol)
start = mid + 1;
- else if (rc_map->scan[mid].scancode > scancode)
+ else if (m->protocol > protocol)
+ end = mid - 1;
+ else if (m->scancode < scancode)
+ start = mid + 1;
+ else if (m->scancode > scancode)
end = mid - 1;
else
return mid;
@@ -439,33 +496,66 @@ static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
static int ir_getkeycode(struct input_dev *idev,
struct input_keymap_entry *ke)
{
+ struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
struct rc_dev *rdev = input_get_drvdata(idev);
struct rc_map *rc_map = &rdev->rc_map;
struct rc_map_table *entry;
unsigned long flags;
unsigned int index;
- unsigned int scancode;
int retval;
spin_lock_irqsave(&rc_map->lock, flags);
if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
index = ke->index;
- } else {
+ } else if (ke->len == sizeof(int)) {
+ /* Legacy EVIOCGKEYCODE ioctl */
+ u32 scancode;
+ u16 protocol;
+
retval = input_scancode_to_scalar(ke, &scancode);
if (retval)
goto out;
- index = ir_lookup_by_scancode(rc_map, scancode);
+ /* Some heuristics to guess the correct protocol */
+ if (hweight64(rdev->enabled_protocols) == 1)
+ protocol = rdev->enabled_protocols;
+ else if (hweight64(rdev->allowed_protos) == 1)
+ protocol = rdev->allowed_protos;
+ else if (rc_map->len > 0)
+ protocol = rc_map->scan[0].protocol;
+ else
+ protocol = RC_TYPE_OTHER;
+
+ index = ir_lookup_by_scancode(rc_map, protocol, scancode);
+
+ } else if (ke->len == sizeof(struct rc_scancode)) {
+ /* New EVIOCGKEYCODE_V2 ioctl */
+ if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[1]) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ index = ir_lookup_by_scancode(rc_map,
+ rke->rc.protocol, rke->rc.scancode);
+
+ } else {
+ retval = -EINVAL;
+ goto out;
}
if (index < rc_map->len) {
entry = &rc_map->scan[index];
-
ke->index = index;
ke->keycode = entry->keycode;
- ke->len = sizeof(entry->scancode);
- memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
+ if (ke->len == sizeof(int)) {
+ u32 scancode = entry->scancode;
+ memcpy(ke->scancode, &scancode, sizeof(scancode));
+ } else {
+ ke->len = sizeof(struct rc_scancode);
+ rke->rc.protocol = entry->protocol;
+ rke->rc.scancode = entry->scancode;
+ }
} else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) {
/*
@@ -490,6 +580,7 @@ out:
/**
* rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
* @dev: the struct rc_dev descriptor of the device
+ * @protocol: the protocol to look for
* @scancode: the scancode to look for
* @return: the corresponding keycode, or KEY_RESERVED
*
@@ -497,7 +588,8 @@ out:
* keycode. Normally it should not be used since drivers should have no
* interest in keycodes.
*/
-u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
+u32 rc_g_keycode_from_table(struct rc_dev *dev,
+ enum rc_type protocol, u64 scancode)
{
struct rc_map *rc_map = &dev->rc_map;
unsigned int keycode;
@@ -506,15 +598,16 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
spin_lock_irqsave(&rc_map->lock, flags);
- index = ir_lookup_by_scancode(rc_map, scancode);
+ index = ir_lookup_by_scancode(rc_map, protocol, scancode);
keycode = index < rc_map->len ?
rc_map->scan[index].keycode : KEY_RESERVED;
spin_unlock_irqrestore(&rc_map->lock, flags);
if (keycode != KEY_RESERVED)
- IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
- dev->input_name, scancode, keycode);
+ IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
+ dev->input_name, protocol,
+ (unsigned long long)scancode, keycode);
return keycode;
}
@@ -616,6 +709,7 @@ EXPORT_SYMBOL_GPL(rc_repeat);
/**
* ir_do_keydown() - internal function to process a keypress
* @dev: the struct rc_dev descriptor of the device
+ * @protocol: the protocol of the keypress
* @scancode: the scancode of the keypress
* @keycode: the keycode of the keypress
* @toggle: the toggle value of the keypress
@@ -623,10 +717,11 @@ EXPORT_SYMBOL_GPL(rc_repeat);
* This function is used internally to register a keypress, it must be
* called with keylock held.
*/
-static void ir_do_keydown(struct rc_dev *dev, int scancode,
- u32 keycode, u8 toggle)
+static void ir_do_keydown(struct rc_dev *dev, u16 protocol,
+ u64 scancode, u32 keycode, u8 toggle)
{
bool new_event = !dev->keypressed ||
+ dev->last_protocol != protocol ||
dev->last_scancode != scancode ||
dev->last_toggle != toggle;
@@ -638,36 +733,39 @@ static void ir_do_keydown(struct rc_dev *dev, int scancode,
if (new_event && keycode != KEY_RESERVED) {
/* Register a keypress */
dev->keypressed = true;
+ dev->last_protocol = protocol;
dev->last_scancode = scancode;
dev->last_toggle = toggle;
dev->last_keycode = keycode;
IR_dprintk(1, "%s: key down event, "
- "key 0x%04x, scancode 0x%04x\n",
- dev->input_name, keycode, scancode);
+ "key 0x%04x, protocol 0x%04x, scancode 0x%08llx\n",
+ dev->input_name, keycode, protocol,
+ (long long unsigned)scancode);
input_report_key(dev->input_dev, keycode, 1);
}
-
input_sync(dev->input_dev);
}
/**
* rc_keydown() - generates input event for a key press
* @dev: the struct rc_dev descriptor of the device
- * @scancode: the scancode that we're seeking
+ * @protocol: the protocol for the keypress
+ * @scancode: the scancode for the keypress
* @toggle: the toggle value (protocol dependent, if the protocol doesn't
* support toggle values, this should be set to zero)
*
* This routine is used to signal that a key has been pressed on the
* remote control.
*/
-void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle)
+void rc_keydown(struct rc_dev *dev, enum rc_type protocol,
+ u64 scancode, u8 toggle)
{
unsigned long flags;
- u32 keycode = rc_g_keycode_from_table(dev, scancode);
+ u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
spin_lock_irqsave(&dev->keylock, flags);
- ir_do_keydown(dev, scancode, keycode, toggle);
+ ir_do_keydown(dev, protocol, scancode, keycode, toggle);
if (dev->keypressed) {
dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
@@ -681,6 +779,7 @@ EXPORT_SYMBOL_GPL(rc_keydown);
* rc_keydown_notimeout() - generates input event for a key press without
* an automatic keyup event at a later time
* @dev: the struct rc_dev descriptor of the device
+ * @protocol: the protocol for the keypress
* @scancode: the scancode that we're seeking
* @toggle: the toggle value (protocol dependent, if the protocol doesn't
* support toggle values, this should be set to zero)
@@ -688,13 +787,14 @@ EXPORT_SYMBOL_GPL(rc_keydown);
* This routine is used to signal that a key has been pressed on the
* remote control. The driver must manually call rc_keyup() at a later stage.
*/
-void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle)
+void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
+ u64 scancode, u8 toggle)
{
unsigned long flags;
- u32 keycode = rc_g_keycode_from_table(dev, scancode);
+ u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
spin_lock_irqsave(&dev->keylock, flags);
- ir_do_keydown(dev, scancode, keycode, toggle);
+ ir_do_keydown(dev, protocol, scancode, keycode, toggle);
spin_unlock_irqrestore(&dev->keylock, flags);
}
EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
@@ -794,13 +894,11 @@ static ssize_t show_protocols(struct device *device,
mutex_lock(&dev->lock);
- if (dev->driver_type == RC_DRIVER_SCANCODE) {
- enabled = dev->rc_map.rc_type;
+ enabled = dev->enabled_protocols;
+ if (dev->driver_type == RC_DRIVER_SCANCODE)
allowed = dev->allowed_protos;
- } else {
- enabled = dev->raw->enabled_protocols;
+ else
allowed = ir_raw_get_allowed_protocols();
- }
IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
(long long)allowed,
@@ -855,7 +953,6 @@ static ssize_t store_protocols(struct device *device,
u64 type;
u64 mask;
int rc, i, count = 0;
- unsigned long flags;
ssize_t ret;
/* Device is being removed */
@@ -864,16 +961,14 @@ static ssize_t store_protocols(struct device *device,
mutex_lock(&dev->lock);
- if (dev->driver_type == RC_DRIVER_SCANCODE)
- type = dev->rc_map.rc_type;
- else if (dev->raw)
- type = dev->raw->enabled_protocols;
- else {
+ if (dev->driver_type != RC_DRIVER_SCANCODE && !dev->raw) {
IR_dprintk(1, "Protocol switching not supported\n");
ret = -EINVAL;
goto out;
}
+ type = dev->enabled_protocols;
+
while ((tmp = strsep((char **) &data, " \n")) != NULL) {
if (!*tmp)
break;
@@ -929,13 +1024,7 @@ static ssize_t store_protocols(struct device *device,
}
}
- if (dev->driver_type == RC_DRIVER_SCANCODE) {
- spin_lock_irqsave(&dev->rc_map.lock, flags);
- dev->rc_map.rc_type = type;
- spin_unlock_irqrestore(&dev->rc_map.lock, flags);
- } else {
- dev->raw->enabled_protocols = type;
- }
+ dev->enabled_protocols = type;
IR_dprintk(1, "Current protocol(s): 0x%llx\n",
(long long)type);
@@ -1135,7 +1224,7 @@ int rc_register_device(struct rc_dev *dev)
}
if (dev->change_protocol) {
- rc = dev->change_protocol(dev, rc_map->rc_type);
+ rc = dev->change_protocol(dev, dev->enabled_protocols);
if (rc < 0)
goto out_raw;
}
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index ef4c7cd..210568f 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -73,12 +73,12 @@ static void ir_handle_key(struct bttv *btv)
if ((ir->mask_keydown && (gpio & ir->mask_keydown)) ||
(ir->mask_keyup && !(gpio & ir->mask_keyup))) {
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
} else {
/* HACK: Probably, ir->mask_keydown is missing
for this board */
if (btv->c.type == BTTV_BOARD_WINFAST2000)
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
rc_keyup(ir->dev);
}
@@ -103,7 +103,7 @@ static void ir_enltv_handle_key(struct bttv *btv)
gpio, data,
(gpio & ir->mask_keyup) ? " up" : "up/down");
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
if (keyup)
rc_keyup(ir->dev);
} else {
@@ -117,7 +117,7 @@ static void ir_enltv_handle_key(struct bttv *btv)
if (keyup)
rc_keyup(ir->dev);
else
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
}
ir->last_gpio = data | keyup;
@@ -235,10 +235,9 @@ static void bttv_rc5_timer_end(unsigned long data)
u32 toggle = RC5_TOGGLE(rc5);
u32 instr = RC5_INSTR(rc5);
- /* Good code */
- rc_keydown(ir->dev, instr, toggle);
- dprintk("instruction %x, toggle %x\n",
- instr, toggle);
+ /* Good code - UNKNOWN, while using legacy code */
+ rc_keydown(ir->dev, RC_TYPE_UNKNOWN, instr, toggle);
+ dprintk("instruction %x, toggle %x\n", instr, toggle);
}
}
}
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index f29e18c..b1922f0 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -130,25 +130,27 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
data = (data << 4) | ((gpio_key & 0xf0) >> 4);
- rc_keydown(ir->dev, data, 0);
+ rc_keydown(ir->dev, ir->dev->allowed_protos, data, 0);
} else if (ir->mask_keydown) {
/* bit set on keydown */
if (gpio & ir->mask_keydown)
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, ir->dev->allowed_protos,
+ data, 0);
else
rc_keyup(ir->dev);
} else if (ir->mask_keyup) {
/* bit cleared on keydown */
if (0 == (gpio & ir->mask_keyup))
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, ir->dev->allowed_protos,
+ data, 0);
else
rc_keyup(ir->dev);
} else {
/* can't distinguish keydown/up :-/ */
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, ir->dev->allowed_protos, data, 0);
rc_keyup(ir->dev);
}
}
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 20a7e24..f1b059d 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -756,6 +756,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_TNF_5335MF,
.tda9887_conf = TDA9887_PRESENT,
.ir_codes = RC_MAP_GADMEI_RM008Z,
+ .ir_protocol = RC_BIT_UNKNOWN,
.decoder = EM28XX_SAA711X,
.xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
.input = { {
@@ -993,6 +994,7 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.dvb_gpio = hauppauge_wintv_hvr_900_digital,
.ir_codes = RC_MAP_HAUPPAUGE,
+ .ir_protocol = RC_BIT_RC5,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -1020,6 +1022,7 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.dvb_gpio = hauppauge_wintv_hvr_900R2_digital,
.ir_codes = RC_MAP_HAUPPAUGE,
+ .ir_protocol = RC_BIT_RC5,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -1046,6 +1049,7 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.dvb_gpio = hauppauge_wintv_hvr_900_digital,
.ir_codes = RC_MAP_HAUPPAUGE,
+ .ir_protocol = RC_BIT_RC5,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -1072,6 +1076,7 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.dvb_gpio = hauppauge_wintv_hvr_900_digital,
.ir_codes = RC_MAP_HAUPPAUGE,
+ .ir_protocol = RC_BIT_RC5,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -1098,6 +1103,7 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.dvb_gpio = hauppauge_wintv_hvr_900_digital,
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
+ .ir_protocol = RC_BIT_UNKNOWN,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -1124,6 +1130,7 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.dvb_gpio = hauppauge_wintv_hvr_900_digital,
.ir_codes = RC_MAP_ATI_TV_WONDER_HD_600,
+ .ir_protocol = RC_BIT_UNKNOWN,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -1150,6 +1157,7 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.dvb_gpio = default_digital,
.ir_codes = RC_MAP_TERRATEC_CINERGY_XS,
+ .ir_protocol = RC_BIT_NEC,
.xclk = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -1512,6 +1520,7 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.dvb_gpio = em2882_kworld_315u_digital,
.ir_codes = RC_MAP_KWORLD_315U,
+ .ir_protocol = RC_BIT_NEC,
.xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE,
/* Analog mode - still not ready */
@@ -1643,6 +1652,7 @@ struct em28xx_board em28xx_boards[] = {
.dvb_gpio = kworld_330u_digital,
.xclk = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */
.ir_codes = RC_MAP_KWORLD_315U,
+ .ir_protocol = RC_BIT_NEC,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
@@ -1666,6 +1676,7 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.dvb_gpio = hauppauge_wintv_hvr_900_digital,
.ir_codes = RC_MAP_TERRATEC_CINERGY_XS,
+ .ir_protocol = RC_BIT_NEC,
.xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -1759,6 +1770,7 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_TVP5150,
.tuner_gpio = default_tuner_gpio,
.ir_codes = RC_MAP_KAIOMY,
+ .ir_protocol = RC_BIT_UNKNOWN,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
@@ -1875,6 +1887,7 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.dvb_gpio = evga_indtube_digital,
.ir_codes = RC_MAP_EVGA_INDTUBE,
+ .ir_protocol = RC_BIT_UNKNOWN,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
@@ -2663,7 +2676,7 @@ static int em28xx_hint_board(struct em28xx *dev)
return -1;
}
-static void em28xx_card_setup(struct em28xx *dev)
+void em28xx_card_setup(struct em28xx *dev)
{
/*
* If the device can be a webcam, seek for a sensor.
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 55808a9..a8c67d8 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -70,7 +70,6 @@ struct em28xx_IR {
/* poll external decoder */
int polling;
struct delayed_work work;
- unsigned int full_code:1;
unsigned int last_readcount;
int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
@@ -297,15 +296,25 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
dprintk("%s: toggle: %d, count: %d, key 0x%02x%02x\n", __func__,
poll_result.toggle_bit, poll_result.read_count,
poll_result.rc_address, poll_result.rc_data[0]);
- if (ir->full_code)
- rc_keydown(ir->rc,
- poll_result.rc_address << 8 |
- poll_result.rc_data[0],
+ switch (ir->rc->enabled_protocols) {
+ case RC_BIT_RC5:
+ rc_keydown(ir->rc, RC_TYPE_RC5,
+ RC_SCANCODE_RC5(poll_result.rc_address,
+ poll_result.rc_data[0]),
poll_result.toggle_bit);
- else
- rc_keydown(ir->rc,
+ break;
+ case RC_BIT_NEC:
+ rc_keydown(ir->rc, RC_TYPE_NEC,
+ RC_SCANCODE_NEC(poll_result.rc_address,
+ poll_result.rc_data[0]),
+ poll_result.toggle_bit);
+ break;
+ default:
+ rc_keydown(ir->rc, RC_TYPE_UNKNOWN,
poll_result.rc_data[0],
poll_result.toggle_bit);
+ break;
+ }
if (ir->dev->chip_id == CHIP_ID_EM2874 ||
ir->dev->chip_id == CHIP_ID_EM2884)
@@ -354,13 +363,11 @@ int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
/* Adjust xclk based o IR table for RC5/NEC tables */
- if (rc_type == RC_BIT_RC5) {
+ if (rc_type == RC_BIT_RC5)
dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
- ir->full_code = 1;
- } else if (rc_type == RC_BIT_NEC) {
+ else if (rc_type == RC_BIT_NEC) {
dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
ir_config = EM2874_IR_NEC;
- ir->full_code = 1;
} else if (rc_type != RC_BIT_UNKNOWN)
rc = -EINVAL;
@@ -550,8 +557,9 @@ static int em28xx_ir_init(struct em28xx *dev)
rc->open = em28xx_ir_start;
rc->close = em28xx_ir_stop;
- /* By default, keep protocol field untouched */
- err = em28xx_ir_change_protocol(rc, RC_BIT_UNKNOWN);
+ /* Set default protocol */
+ rc->enabled_protocols = dev->board.ir_protocol;
+ err = em28xx_ir_change_protocol(rc, dev->board.ir_protocol);
if (err)
goto err_out_free;
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 8757523..745a24c 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -413,6 +413,7 @@ struct em28xx_board {
struct em28xx_input input[MAX_EM28XX_INPUT];
struct em28xx_input radio;
char *ir_codes;
+ u64 ir_protocol; /* default protocol */
};
struct em28xx_eeprom {
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 08ae067..86c53fa 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -108,7 +108,7 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
start, range, toggle, dev, code);
/* return key */
- *ir_key = (dev << 8) | code;
+ *ir_key = RC_SCANCODE_RC5(dev, code);
*ir_raw = ircode;
return 1;
}
@@ -258,7 +258,14 @@ static int ir_key_poll(struct IR_i2c *ir)
if (rc) {
dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key);
- rc_keydown(ir->rc, ir_key, 0);
+ switch (ir->rc->enabled_protocols) {
+ case RC_BIT_RC5:
+ rc_keydown(ir->rc, RC_TYPE_RC5, ir_key, 0);
+ break;
+ default:
+ rc_keydown(ir->rc, RC_TYPE_UNKNOWN, ir_key, 0);
+ break;
+ }
}
return 0;
}
@@ -423,6 +430,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
*/
rc->map_name = ir->ir_codes;
rc->allowed_protos = rc_type;
+ rc->enabled_protocols = rc_type;
if (!rc->driver_name)
rc->driver_name = MODULE_NAME;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 6ad49c6..6b5fc7f 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -83,14 +83,14 @@ static int build_key(struct saa7134_dev *dev)
if (data == ir->mask_keycode)
rc_keyup(ir->dev);
else
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
return 0;
}
if (ir->polling) {
if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
(ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
} else {
rc_keyup(ir->dev);
}
@@ -98,7 +98,7 @@ static int build_key(struct saa7134_dev *dev)
else { /* IRQ driven mode - handle key press and release in one go */
if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
(ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
rc_keyup(ir->dev);
}
}
diff --git a/drivers/media/video/tm6000/tm6000-cards.c b/drivers/media/video/tm6000/tm6000-cards.c
index 034659b..e45c047 100644
--- a/drivers/media/video/tm6000/tm6000-cards.c
+++ b/drivers/media/video/tm6000/tm6000-cards.c
@@ -85,6 +85,7 @@ struct tm6000_board {
struct tm6000_input rinput;
char *ir_codes;
+ u64 ir_protocol;
};
static struct tm6000_board tm6000_boards[] = {
@@ -481,6 +482,7 @@ static struct tm6000_board tm6000_boards[] = {
.ir = TM6010_GPIO_0,
},
.ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
+ .ir_protocol = RC_BIT_UNKNOWN,
.vinput = { {
.type = TM6000_INPUT_TV,
.vmux = TM6000_VMUX_VIDEO_B,
diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c
index 8ce028f..6fc0a71 100644
--- a/drivers/media/video/tm6000/tm6000-input.c
+++ b/drivers/media/video/tm6000/tm6000-input.c
@@ -51,10 +51,6 @@ MODULE_PARM_DESC(enable_ir, "ir clock, in MHz");
printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
} while (0)
-struct tm6000_ir_poll_result {
- u16 rc_data;
-};
-
struct tm6000_IR {
struct tm6000_core *dev;
struct rc_dev *rc;
@@ -162,12 +158,43 @@ static int tm6000_ir_config(struct tm6000_IR *ir)
return 0;
}
+static void tm6000_ir_keydown(struct tm6000_IR *ir,
+ const char *buf, unsigned int len)
+{
+ u8 device, command;
+ u64 scancode;
+ enum rc_type protocol;
+
+ if (len < 1)
+ return;
+
+ command = buf[0];
+ device = (len > 1 ? buf[1] : 0x0);
+ switch (ir->rc_type) {
+ case RC_BIT_RC5:
+ protocol = RC_TYPE_RC5;
+ scancode = RC_SCANCODE_RC5(device, command);
+ break;
+ case RC_BIT_NEC:
+ protocol = RC_TYPE_NEC;
+ scancode = RC_SCANCODE_NEC(device, command);
+ break;
+ default:
+ protocol = RC_TYPE_OTHER;
+ scancode = RC_SCANCODE_OTHER(device << 8 | command);
+ break;
+ }
+
+ dprintk(1, "%s, protocol: 0x%04x, scancode: 0x%08llx\n",
+ __func__, protocol, (unsigned long long)scancode);
+ rc_keydown(ir->rc, protocol, scancode, 0);
+}
+
static void tm6000_ir_urb_received(struct urb *urb)
{
struct tm6000_core *dev = urb->context;
struct tm6000_IR *ir = dev->ir;
- struct tm6000_ir_poll_result poll_result;
- char *buf;
+ int rc;
dprintk(2, "%s\n",__func__);
if (urb->status < 0 || urb->actual_length <= 0) {
@@ -177,19 +204,14 @@ static void tm6000_ir_urb_received(struct urb *urb)
schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY));
return;
}
- buf = urb->transfer_buffer;
if (ir_debug)
print_hex_dump(KERN_DEBUG, "tm6000: IR data: ",
DUMP_PREFIX_OFFSET,16, 1,
- buf, urb->actual_length, false);
-
- poll_result.rc_data = buf[0];
- if (urb->actual_length > 1)
- poll_result.rc_data |= buf[1] << 8;
+ urb->transfer_buffer, urb->actual_length,
+ false);
- dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data);
- rc_keydown(ir->rc, poll_result.rc_data, 0);
+ tm6000_ir_keydown(ir, urb->transfer_buffer, urb->actual_length);
usb_submit_urb(urb, GFP_ATOMIC);
/*
@@ -204,7 +226,6 @@ static void tm6000_ir_handle_key(struct work_struct *work)
{
struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
struct tm6000_core *dev = ir->dev;
- struct tm6000_ir_poll_result poll_result;
int rc;
u8 buf[2];
@@ -219,13 +240,8 @@ static void tm6000_ir_handle_key(struct work_struct *work)
if (rc < 0)
return;
- if (rc > 1)
- poll_result.rc_data = buf[0] | buf[1] << 8;
- else
- poll_result.rc_data = buf[0];
-
/* Check if something was read */
- if ((poll_result.rc_data & 0xff) == 0xff) {
+ if ((buf[0] & 0xff) == 0xff) {
if (!ir->pwled) {
tm6000_flash_led(dev, 1);
ir->pwled = 1;
@@ -233,8 +249,7 @@ static void tm6000_ir_handle_key(struct work_struct *work)
return;
}
- dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data);
- rc_keydown(ir->rc, poll_result.rc_data, 0);
+ tm6000_ir_keydown(ir, buf, rc);
tm6000_flash_led(dev, 0);
ir->pwled = 0;
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 58f12da..0045292 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -34,6 +34,24 @@ enum rc_driver_type {
RC_DRIVER_IR_RAW, /* Needs a Infra-Red pulse/space decoder */
};
+/* This is used for the input EVIOC[SG]KEYCODE_V2 ioctls */
+struct rc_scancode {
+ __u16 protocol;
+ __u16 reserved[3];
+ __u64 scancode;
+};
+
+struct rc_keymap_entry {
+ __u8 flags;
+ __u8 len;
+ __u16 index;
+ __u32 keycode;
+ union {
+ struct rc_scancode rc;
+ __u8 raw[32];
+ };
+};
+
/**
* struct rc_dev - represents a remote control device
* @dev: driver model's view of this device
@@ -99,6 +117,7 @@ struct rc_dev {
enum rc_driver_type driver_type;
bool idle;
u64 allowed_protos;
+ u64 enabled_protocols;
u32 scanmask;
void *priv;
spinlock_t keylock;
@@ -106,7 +125,8 @@ struct rc_dev {
unsigned long keyup_jiffies;
struct timer_list timer_keyup;
u32 last_keycode;
- u32 last_scancode;
+ enum rc_type last_protocol;
+ u64 last_scancode;
u8 last_toggle;
u32 timeout;
u32 min_timeout;
@@ -141,10 +161,10 @@ int rc_register_device(struct rc_dev *dev);
void rc_unregister_device(struct rc_dev *dev);
void rc_repeat(struct rc_dev *dev);
-void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle);
-void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle);
+void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u64 scancode, u8 toggle);
+void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol, u64 scancode, u8 toggle);
void rc_keyup(struct rc_dev *dev);
-u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode);
+u32 rc_g_keycode_from_table(struct rc_dev *dev, enum rc_type protocol, u64 scancode);
/*
* From rc-raw.c
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 909c2ed..48af876 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -60,9 +60,20 @@ enum rc_type {
RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE)
+#define RC_SCANCODE_UNKNOWN(x) (x)
+#define RC_SCANCODE_OTHER(x) (x)
+#define RC_SCANCODE_NEC(addr, cmd) (((addr) << 8) | (cmd))
+#define RC_SCANCODE_NECX(addr, cmd) (((addr) << 8) | (cmd))
+#define RC_SCANCODE_NEC32(data) ((data) & 0xffffffff)
+#define RC_SCANCODE_RC5(sys, cmd) (((sys) << 8) | (cmd))
+#define RC_SCANCODE_RC5_SZ(sys, cmd) (((sys) << 8) | (cmd))
+#define RC_SCANCODE_RC6_0(sys, cmd) (((sys) << 8) | (cmd))
+#define RC_SCANCODE_RC6_6A(vendor, sys, cmd) (((vendor) << 16) | ((sys) << 8) | (cmd))
+
struct rc_map_table {
- u32 scancode;
- u32 keycode;
+ u64 scancode;
+ u32 keycode;
+ enum rc_type protocol;
};
struct rc_map {
@@ -70,7 +81,7 @@ struct rc_map {
unsigned int size; /* Max number of entries */
unsigned int len; /* Used number of entries */
unsigned int alloc; /* Size of *scan in bytes */
- enum rc_type rc_type;
+ enum rc_type rc_type; /* For in-kernel keymaps */
const char *name;
spinlock_t lock;
};
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 04/43] rc-core: use the full 32 bits for NEC scancodes
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (2 preceding siblings ...)
2012-05-23 9:42 ` [PATCH 03/43] rc-core: don't throw away protocol information David Härdeman
@ 2012-05-23 9:42 ` David Härdeman
2012-05-23 9:42 ` [PATCH 05/43] rc-core: merge rc5 and streamzap decoders David Härdeman
` (39 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:42 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Using the full 32 bits for all kinds of NEC scancodes simplifies rc-core
and the nec decoder without any loss of functionality.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/dvb/dvb-usb/af9015.c | 22 ++++++----------------
drivers/media/dvb/dvb-usb/af9035.c | 20 +++-----------------
drivers/media/dvb/dvb-usb/az6007.c | 16 ++++------------
drivers/media/dvb/dvb-usb/it913x.c | 15 ++++++---------
drivers/media/dvb/dvb-usb/rtl28xxu.c | 21 ++++-----------------
drivers/media/rc/ir-nec-decoder.c | 28 ++++------------------------
include/media/rc-map.h | 11 +++++++++--
7 files changed, 36 insertions(+), 97 deletions(-)
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index bd47e68..4733044 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -1046,7 +1046,8 @@ static int af9015_rc_query(struct dvb_usb_device *d)
if ((priv->rc_repeat != buf[6] || buf[0]) &&
!memcmp(&buf[12], priv->rc_last, 4)) {
deb_rc("%s: key repeated\n", __func__);
- rc_keydown(d->rc_dev, RC_TYPE_NEC, priv->rc_keycode, 0);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC,
+ RC_SCANCODE_NEC32(priv->rc_keycode), 0);
priv->rc_repeat = buf[6];
return ret;
}
@@ -1063,21 +1064,10 @@ static int af9015_rc_query(struct dvb_usb_device *d)
/* Remember this key */
memcpy(priv->rc_last, &buf[12], 4);
- if (buf[14] == (u8) ~buf[15]) {
- if (buf[12] == (u8) ~buf[13]) {
- /* NEC */
- priv->rc_keycode = buf[12] << 8 | buf[14];
- } else {
- /* NEC extended*/
- priv->rc_keycode = buf[12] << 16 |
- buf[13] << 8 | buf[14];
- }
- } else {
- /* 32 bit NEC */
- priv->rc_keycode = buf[12] << 24 | buf[13] << 16 |
- buf[14] << 8 | buf[15];
- }
- rc_keydown(d->rc_dev, RC_TYPE_NEC, priv->rc_keycode, 0);
+ priv->rc_keycode = buf[12] << 24 | buf[13] << 16 |
+ buf[14] << 8 | buf[15];
+ rc_keydown(d->rc_dev, RC_TYPE_NEC,
+ RC_SCANCODE_NEC32(priv->rc_keycode), 0);
} else {
deb_rc("%s: no key press\n", __func__);
/* Invalidate last keypress */
diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c
index c000feb..42094e1 100644
--- a/drivers/media/dvb/dvb-usb/af9035.c
+++ b/drivers/media/dvb/dvb-usb/af9035.c
@@ -311,24 +311,10 @@ static int af9035_rc_query(struct dvb_usb_device *d)
ret = af9035_ctrl_msg(d->udev, &req);
if (ret < 0)
- goto err;
-
- if ((b[2] + b[3]) == 0xff) {
- if ((b[0] + b[1]) == 0xff) {
- /* NEC */
- key = b[0] << 8 | b[2];
- } else {
- /* ext. NEC */
- key = b[0] << 16 | b[1] << 8 | b[2];
- }
- } else {
- key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
- }
-
- rc_keydown(d->rc_dev, RC_TYPE_NEC, key, 0);
+ return 0;
-err:
- /* ignore errors */
+ key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
+ rc_keydown(d->rc_dev, RC_TYPE_NEC, RC_SCANCODE_NEC32(key), 0);
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/az6007.c b/drivers/media/dvb/dvb-usb/az6007.c
index 1e26863..1e5888f 100644
--- a/drivers/media/dvb/dvb-usb/az6007.c
+++ b/drivers/media/dvb/dvb-usb/az6007.c
@@ -204,18 +204,10 @@ static int az6007_rc_query(struct dvb_usb_device *d)
if (st->data[1] == 0x44)
return 0;
- if ((st->data[3] ^ st->data[4]) == 0xff) {
- if ((st->data[1] ^ st->data[2]) == 0xff)
- code = RC_SCANCODE_NEC(st->data[1], st->data[3]);
- else
- code = RC_SCANCODE_NECX(st->data[1] << 8 | st->data[2],
- st->data[3]);
- } else {
- code = RC_SCANCODE_NEC32(st->data[1] << 24 |
- st->data[2] << 16 |
- st->data[3] << 8 |
- st->data[4]);
- }
+ code = RC_SCANCODE_NEC32(st->data[1] << 24 |
+ st->data[2] << 16 |
+ st->data[3] << 8 |
+ st->data[4]);
rc_keydown(d->rc_dev, RC_TYPE_NEC, code, st->data[5]);
diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c
index 2c3c400..59d3f07 100644
--- a/drivers/media/dvb/dvb-usb/it913x.c
+++ b/drivers/media/dvb/dvb-usb/it913x.c
@@ -381,7 +381,6 @@ static int it913x_rc_query(struct dvb_usb_device *d)
{
u8 ibuf[4];
int ret;
- u16 device, command;
u64 scancode;
if (!d->rc_dev)
@@ -393,14 +392,12 @@ static int it913x_rc_query(struct dvb_usb_device *d)
ret = it913x_io(d->udev, READ_LONG, PRO_LINK, CMD_IR_GET,
0, 0, &ibuf[0], sizeof(ibuf));
- if ((ibuf[2] + ibuf[3]) == 0xff) {
- command = ibuf[2];
- device = (ibuf[0] << 8) | ibuf[1];
- scancode = RC_SCANCODE_NECX(device, command);
- deb_info(1, "NEC Extended Key = 0x%08llx",
- (unsigned long long)scancode);
- rc_keydown(d->rc_dev, RC_TYPE_NEC, scancode, 0);
- }
+ scancode = RC_SCANCODE_NEC32(ibuf[0] << 24 |
+ ibuf[1] << 16 |
+ ibuf[2] << 8 |
+ ibuf[3] << 0);
+ deb_info(1, "NEC32 Key = 0x%08llx", (unsigned long long)scancode);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC, scancode, 0);
mutex_unlock(&d->i2c_mutex);
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c
index b2749d8..9dbde0a 100644
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.c
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c
@@ -673,23 +673,10 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
goto err;
if (buf[4] & 0x01) {
- if (buf[2] == (u8) ~buf[3]) {
- if (buf[0] == (u8) ~buf[1]) {
- /* NEC standard (16 bit) */
- rc_code = RC_SCANCODE_NEC(buf[0], buf[2]);
- } else {
- /* NEC extended (24 bit) */
- rc_code = RC_SCANCODE_NECX(buf[0] << 8 |
- buf[1],
- buf[2]);
- }
- } else {
- /* NEC full (32 bit) */
- rc_code = RC_SCANCODE_NEC32(buf[0] << 24 |
- buf[1] << 16 |
- buf[2] << 8 |
- buf[3]);
- }
+ rc_code = RC_SCANCODE_NEC32(buf[0] << 24 |
+ buf[1] << 16 |
+ buf[2] << 8 |
+ buf[3]);
rc_keydown(d->rc_dev, RC_TYPE_NEC, rc_code, 0);
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 535e6e2..1033f30 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -50,7 +50,6 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
struct nec_dec *data = &dev->raw->nec;
u32 scancode;
u8 address, not_address, command, not_command;
- bool send_32bits = false;
if (!(dev->enabled_protocols & RC_BIT_NEC))
return 0;
@@ -163,33 +162,14 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
command = bitrev8((data->bits >> 8) & 0xff);
not_command = bitrev8((data->bits >> 0) & 0xff);
- if ((command ^ not_command) != 0xff) {
- IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
- data->bits);
- send_32bits = true;
- }
-
- if (send_32bits) {
- /* NEC transport, but modified protocol, used by at
- * least Apple and TiVo remotes */
- scancode = data->bits;
- IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode);
- } else if ((address ^ not_address) != 0xff) {
- /* Extended NEC */
- scancode = address << 16 |
- not_address << 8 |
- command;
- IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode);
- } else {
- /* Normal NEC */
- scancode = address << 8 | command;
- IR_dprintk(1, "NEC scancode 0x%04x\n", scancode);
- }
+ scancode = address << 24 | not_address << 16 |
+ command << 8 | not_command;
+ IR_dprintk(1, "NEC scancode 0x%08x\n", scancode);
if (data->is_nec_x)
data->necx_repeat = true;
- rc_keydown(dev, RC_TYPE_NEC, scancode, 0);
+ rc_keydown(dev, RC_TYPE_NEC, RC_SCANCODE_NEC32(scancode), 0);
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 48af876..7de8215 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -62,8 +62,15 @@ enum rc_type {
#define RC_SCANCODE_UNKNOWN(x) (x)
#define RC_SCANCODE_OTHER(x) (x)
-#define RC_SCANCODE_NEC(addr, cmd) (((addr) << 8) | (cmd))
-#define RC_SCANCODE_NECX(addr, cmd) (((addr) << 8) | (cmd))
+#define RC_SCANCODE_NEC(addr, cmd) \
+ ((( (addr) & 0xff) << 24) | \
+ ((~(addr) & 0xff) << 16) | \
+ (( (cmd) & 0xff) << 8 ) | \
+ ((~(cmd) & 0xff) << 0 ))
+#define RC_SCANCODE_NECX(addr, cmd) \
+ ((( (addr) & 0xffff) << 16) | \
+ (( (cmd) & 0x00ff) << 8) | \
+ ((~(cmd) & 0x00ff) << 0))
#define RC_SCANCODE_NEC32(data) ((data) & 0xffffffff)
#define RC_SCANCODE_RC5(sys, cmd) (((sys) << 8) | (cmd))
#define RC_SCANCODE_RC5_SZ(sys, cmd) (((sys) << 8) | (cmd))
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 05/43] rc-core: merge rc5 and streamzap decoders
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (3 preceding siblings ...)
2012-05-23 9:42 ` [PATCH 04/43] rc-core: use the full 32 bits for NEC scancodes David Härdeman
@ 2012-05-23 9:42 ` David Härdeman
2012-05-23 9:42 ` [PATCH 06/43] rc-core: rename ir_input_class to rc_class David Härdeman
` (38 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:42 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Now that the protocol is part of the scancode, it is pretty easy to merge
the rc5 and streamzap decoders. An additional advantage is that the decoder
is now stricter as it waits for the trailing silence before determining that
a command is a valid rc5/streamzap command (which avoids collisions that I've
seen with e.g. Sony protocols).
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/Kconfig | 12 --
drivers/media/rc/Makefile | 1
drivers/media/rc/ir-rc5-decoder.c | 51 ++++++----
drivers/media/rc/ir-rc5-sz-decoder.c | 154 -------------------------------
drivers/media/rc/keymaps/rc-streamzap.c | 4 -
drivers/media/rc/rc-core-priv.h | 8 --
drivers/media/rc/streamzap.c | 10 --
7 files changed, 31 insertions(+), 209 deletions(-)
delete mode 100644 drivers/media/rc/ir-rc5-sz-decoder.c
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index f97eeb8..090872b 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -76,18 +76,6 @@ config IR_SONY_DECODER
Enable this option if you have an infrared remote control which
uses the Sony protocol, and you need software decoding support.
-config IR_RC5_SZ_DECODER
- tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol"
- depends on RC_CORE
- select BITREVERSE
- default y
-
- ---help---
- Enable this option if you have IR with RC-5 (streamzap) protocol,
- and if the IR is decoded in software. (The Streamzap PC Remote
- uses an IR protocol that is almost standard RC-5, but not quite,
- as it uses an additional bit).
-
config IR_SANYO_DECODER
tristate "Enable IR raw decoder for the Sanyo protocol"
depends on RC_CORE
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 29f364f..596060a 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
-obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o
obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index ddbf9bf..9594b8f 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -1,6 +1,7 @@
-/* ir-rc5-decoder.c - handle RC5(x) IR Pulse/Space protocol
+/* ir-rc5-decoder.c - decoder for RC5(x) and StreamZap protocols
*
* Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * 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
@@ -13,23 +14,22 @@
*/
/*
- * This code handles 14 bits RC5 protocols and 20 bits RC5x protocols.
- * There are other variants that use a different number of bits.
- * This is currently unsupported.
- * It considers a carrier of 36 kHz, with a total of 14/20 bits, where
- * the first two bits are start bits, and a third one is a filing bit
+ * This decoder handles the 14 bit RC5 protocol, 15 bit "StreamZap" protocol
+ * and 20 bit RC5x protocol.
*/
#include "rc-core-priv.h"
#include <linux/module.h>
#define RC5_NBITS 14
+#define RC5_SZ_NBITS 15
#define RC5X_NBITS 20
#define CHECK_RC5X_NBITS 8
#define RC5_UNIT 888888 /* ns */
#define RC5_BIT_START (1 * RC5_UNIT)
#define RC5_BIT_END (1 * RC5_UNIT)
#define RC5X_SPACE (4 * RC5_UNIT)
+#define RC5_TRAILER (10 * RC5_UNIT) /* In reality, approx 100 */
enum rc5_state {
STATE_INACTIVE,
@@ -80,12 +80,15 @@ again:
data->state = STATE_BIT_START;
data->count = 1;
- /* We just need enough bits to get to STATE_CHECK_RC5X */
- data->wanted_bits = RC5X_NBITS;
decrease_duration(&ev, RC5_BIT_START);
goto again;
case STATE_BIT_START:
+ if (!ev.pulse && geq_margin(ev.duration, RC5_TRAILER, RC5_UNIT / 2)) {
+ data->state = STATE_FINISHED;
+ goto again;
+ }
+
if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
break;
@@ -100,9 +103,7 @@ again:
if (!is_transition(&ev, &dev->raw->prev_ev))
break;
- if (data->count == data->wanted_bits)
- data->state = STATE_FINISHED;
- else if (data->count == CHECK_RC5X_NBITS)
+ if (data->count == CHECK_RC5X_NBITS)
data->state = STATE_CHECK_RC5X;
else
data->state = STATE_BIT_START;
@@ -112,13 +113,10 @@ again:
case STATE_CHECK_RC5X:
if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
- /* RC5X */
- data->wanted_bits = RC5X_NBITS;
+ data->is_rc5x = true;
decrease_duration(&ev, RC5X_SPACE);
- } else {
- /* RC5 */
- data->wanted_bits = RC5_NBITS;
- }
+ } else
+ data->is_rc5x = false;
data->state = STATE_BIT_START;
goto again;
@@ -126,7 +124,7 @@ again:
if (ev.pulse)
break;
- if (data->wanted_bits == RC5X_NBITS) {
+ if (data->is_rc5x && data->count == RC5X_NBITS) {
/* RC5X */
u8 xdata, command, system;
xdata = (data->bits & 0x0003F) >> 0;
@@ -136,7 +134,7 @@ again:
command += (data->bits & 0x01000) ? 0 : 0x40;
scancode = system << 16 | command << 8 | xdata;
protocol = RC_TYPE_RC5X;
- } else {
+ } else if (!data->is_rc5x && data->count == RC5_NBITS) {
/* RC5 */
u8 command, system;
command = (data->bits & 0x0003F) >> 0;
@@ -145,10 +143,19 @@ again:
command += (data->bits & 0x01000) ? 0 : 0x40;
scancode = system << 8 | command;
protocol = RC_TYPE_RC5;
- }
+ } else if (!data->is_rc5x && data->count == RC5_SZ_NBITS) {
+ /* RC5 StreamZap */
+ u8 command, system;
+ command = (data->bits & 0x0003F) >> 0;
+ system = (data->bits & 0x02FC0) >> 6;
+ toggle = (data->bits & 0x01000) ? 1 : 0;
+ scancode = system << 6 | command;
+ protocol = RC_TYPE_RC5_SZ;
+ } else
+ break;
if (dev->enabled_protocols & (1 << protocol)) {
- IR_dprintk(1, "RC5(x) scancode 0x%06x (toggle: %u)\n",
+ IR_dprintk(1, "RC5(x/sz) scancode 0x%06x (toggle: %u)\n",
scancode, toggle);
rc_keydown(dev, protocol, scancode, toggle);
}
@@ -165,7 +172,7 @@ out:
}
static struct ir_raw_handler rc5_handler = {
- .protocols = RC_BIT_RC5 | RC_BIT_RC5X,
+ .protocols = RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ,
.decode = ir_rc5_decode,
};
diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c
deleted file mode 100644
index 8681b96..0000000
--- a/drivers/media/rc/ir-rc5-sz-decoder.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol
- *
- * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- * Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/*
- * This code handles the 15 bit RC5-ish protocol used by the Streamzap
- * PC Remote.
- * It considers a carrier of 36 kHz, with a total of 15 bits, where
- * the first two bits are start bits, and a third one is a filing bit
- */
-
-#include "rc-core-priv.h"
-#include <linux/module.h>
-
-#define RC5_SZ_NBITS 15
-#define RC5_UNIT 888888 /* ns */
-#define RC5_BIT_START (1 * RC5_UNIT)
-#define RC5_BIT_END (1 * RC5_UNIT)
-
-enum rc5_sz_state {
- STATE_INACTIVE,
- STATE_BIT_START,
- STATE_BIT_END,
- STATE_FINISHED,
-};
-
-/**
- * ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space
- * @dev: the struct rc_dev descriptor of the device
- * @ev: the struct ir_raw_event descriptor of the pulse/space
- *
- * This function returns -EINVAL if the pulse violates the state machine
- */
-static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev)
-{
- struct rc5_sz_dec *data = &dev->raw->rc5_sz;
- u8 toggle, command, system;
- u32 scancode;
-
- if (!(dev->enabled_protocols & RC_BIT_RC5_SZ))
- return 0;
-
- if (!is_timing_event(ev)) {
- if (ev.reset)
- data->state = STATE_INACTIVE;
- return 0;
- }
-
- if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
- goto out;
-
-again:
- IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
-
- if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
- return 0;
-
- switch (data->state) {
-
- case STATE_INACTIVE:
- if (!ev.pulse)
- break;
-
- data->state = STATE_BIT_START;
- data->count = 1;
- data->wanted_bits = RC5_SZ_NBITS;
- decrease_duration(&ev, RC5_BIT_START);
- goto again;
-
- case STATE_BIT_START:
- if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
- break;
-
- data->bits <<= 1;
- if (!ev.pulse)
- data->bits |= 1;
- data->count++;
- data->state = STATE_BIT_END;
- return 0;
-
- case STATE_BIT_END:
- if (!is_transition(&ev, &dev->raw->prev_ev))
- break;
-
- if (data->count == data->wanted_bits)
- data->state = STATE_FINISHED;
- else
- data->state = STATE_BIT_START;
-
- decrease_duration(&ev, RC5_BIT_END);
- goto again;
-
- case STATE_FINISHED:
- if (ev.pulse)
- break;
-
- /* RC5-sz */
- command = (data->bits & 0x0003F) >> 0;
- system = (data->bits & 0x02FC0) >> 6;
- toggle = (data->bits & 0x01000) ? 1 : 0;
- scancode = system << 6 | command;
-
- IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n",
- scancode, toggle);
-
- rc_keydown(dev, RC_TYPE_RC5_SZ, scancode, toggle);
- data->state = STATE_INACTIVE;
- return 0;
- }
-
-out:
- IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
- data->state = STATE_INACTIVE;
- return -EINVAL;
-}
-
-static struct ir_raw_handler rc5_sz_handler = {
- .protocols = RC_BIT_RC5_SZ,
- .decode = ir_rc5_sz_decode,
-};
-
-static int __init ir_rc5_sz_decode_init(void)
-{
- ir_raw_handler_register(&rc5_sz_handler);
-
- printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n");
- return 0;
-}
-
-static void __exit ir_rc5_sz_decode_exit(void)
-{
- ir_raw_handler_unregister(&rc5_sz_handler);
-}
-
-module_init(ir_rc5_sz_decode_init);
-module_exit(ir_rc5_sz_decode_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
-MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
-MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder");
diff --git a/drivers/media/rc/keymaps/rc-streamzap.c b/drivers/media/rc/keymaps/rc-streamzap.c
index f9a0757..23c0611 100644
--- a/drivers/media/rc/keymaps/rc-streamzap.c
+++ b/drivers/media/rc/keymaps/rc-streamzap.c
@@ -15,9 +15,7 @@
static struct rc_map_table streamzap[] = {
/*
* The Streamzap remote is almost, but not quite, RC-5, as it has an extra
- * bit in it, which throws the in-kernel RC-5 decoder for a loop. Currently,
- * an additional RC-5-sz decoder is being deployed to support it, but it
- * may be possible to merge it back with the standard RC-5 decoder.
+ * bit in it.
*/
{ 0x28c0, KEY_NUMERIC_0 },
{ 0x28c1, KEY_NUMERIC_1 },
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 4de2d47..6a40bc9 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -54,7 +54,7 @@ struct ir_raw_event_ctrl {
int state;
u32 bits;
unsigned count;
- unsigned wanted_bits;
+ bool is_rc5x;
} rc5;
struct rc6_dec {
int state;
@@ -77,12 +77,6 @@ struct ir_raw_event_ctrl {
bool first;
bool toggle;
} jvc;
- struct rc5_sz_dec {
- int state;
- u32 bits;
- unsigned count;
- unsigned wanted_bits;
- } rc5_sz;
struct sanyo_dec {
int state;
unsigned count;
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index c720f12..fdfedc6 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -69,13 +69,6 @@ MODULE_DEVICE_TABLE(usb, streamzap_table);
/* number of samples buffered */
#define SZ_BUF_LEN 128
-/* from ir-rc5-sz-decoder.c */
-#ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE
-#define load_rc5_sz_decode() request_module("ir-rc5-sz-decoder")
-#else
-#define load_rc5_sz_decode() {}
-#endif
-
enum StreamzapDecoderState {
PulseSpace,
FullPulse,
@@ -458,9 +451,6 @@ static int __devinit streamzap_probe(struct usb_interface *intf,
dev_info(sz->dev, "Registered %s on usb%d:%d\n", name,
usbdev->bus->busnum, usbdev->devnum);
- /* Load the streamzap not-quite-rc5 decoder too */
- load_rc5_sz_decode();
-
return 0;
rc_dev_fail:
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 06/43] rc-core: rename ir_input_class to rc_class
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (4 preceding siblings ...)
2012-05-23 9:42 ` [PATCH 05/43] rc-core: merge rc5 and streamzap decoders David Härdeman
@ 2012-05-23 9:42 ` David Härdeman
2012-05-23 9:42 ` [PATCH 07/43] rc-core: initialize rc-core earlier if built-in David Härdeman
` (37 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:42 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
The name is already misleading and will be more so in the future as the
connection to the input subsystem is obscured away further.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-main.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 4adaa87..0e50a84 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -815,14 +815,14 @@ static void ir_close(struct input_dev *idev)
}
/* class for /sys/class/rc */
-static char *ir_devnode(struct device *dev, umode_t *mode)
+static char *rc_devnode(struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev));
}
-static struct class ir_input_class = {
+static struct class rc_class = {
.name = "rc",
- .devnode = ir_devnode,
+ .devnode = rc_devnode,
};
/*
@@ -1112,7 +1112,7 @@ struct rc_dev *rc_allocate_device(void)
setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev);
dev->dev.type = &rc_dev_type;
- dev->dev.class = &ir_input_class;
+ dev->dev.class = &rc_class;
device_initialize(&dev->dev);
__module_get(THIS_MODULE);
@@ -1285,7 +1285,7 @@ EXPORT_SYMBOL_GPL(rc_unregister_device);
static int __init rc_core_init(void)
{
- int rc = class_register(&ir_input_class);
+ int rc = class_register(&rc_class);
if (rc) {
printk(KERN_ERR "rc_core: unable to register rc class\n");
return rc;
@@ -1298,7 +1298,7 @@ static int __init rc_core_init(void)
static void __exit rc_core_exit(void)
{
- class_unregister(&ir_input_class);
+ class_unregister(&rc_class);
rc_map_unregister(&empty_map);
}
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 07/43] rc-core: initialize rc-core earlier if built-in
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (5 preceding siblings ...)
2012-05-23 9:42 ` [PATCH 06/43] rc-core: rename ir_input_class to rc_class David Härdeman
@ 2012-05-23 9:42 ` David Härdeman
2012-05-23 9:42 ` [PATCH 08/43] rc-core: use a device table rather than an atomic number David Härdeman
` (36 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:42 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
rc-core is a subsystem so it should be registered earlier if built into the
kernel.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 0e50a84..6e02314 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1302,7 +1302,7 @@ static void __exit rc_core_exit(void)
rc_map_unregister(&empty_map);
}
-module_init(rc_core_init);
+subsys_initcall(rc_core_init);
module_exit(rc_core_exit);
int rc_core_debug; /* ir_debug level (0,1,2) */
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 08/43] rc-core: use a device table rather than an atomic number
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (6 preceding siblings ...)
2012-05-23 9:42 ` [PATCH 07/43] rc-core: initialize rc-core earlier if built-in David Härdeman
@ 2012-05-23 9:42 ` David Härdeman
2012-05-23 9:42 ` [PATCH 09/43] rc-core: add chardev David Härdeman
` (35 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:42 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
This patch changes rc-core to use a device table rather than atomic integers
to assign unique numbers to each rc device. This is in preparation for
introducing rc-core chardevs.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/ir-raw.c | 2 +-
drivers/media/rc/rc-main.c | 41 +++++++++++++++++++++++++++++++++++------
include/media/rc-core.h | 4 ++--
3 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 6b3c9e5..7729abe 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -268,7 +268,7 @@ int ir_raw_event_register(struct rc_dev *dev)
spin_lock_init(&dev->raw->lock);
dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
- "rc%ld", dev->devno);
+ "rc%u", dev->minor);
if (IS_ERR(dev->raw->thread)) {
rc = PTR_ERR(dev->raw->thread);
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 6e02314..8da7701 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -24,6 +24,7 @@
/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
#define IR_TAB_MIN_SIZE 256
#define IR_TAB_MAX_SIZE 8192
+#define RC_DEV_MAX 32
/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
#define IR_KEYPRESS_TIMEOUT 250
@@ -32,6 +33,10 @@
static LIST_HEAD(rc_map_list);
static DEFINE_SPINLOCK(rc_map_lock);
+/* Various bits and pieces to keep track of rc devices */
+static struct rc_dev *rc_dev_table[RC_DEV_MAX];
+static DEFINE_MUTEX(rc_dev_table_mutex);
+
static struct rc_map_list *seek_rc_map(const char *name)
{
struct rc_map_list *map = NULL;
@@ -1138,10 +1143,10 @@ EXPORT_SYMBOL_GPL(rc_free_device);
int rc_register_device(struct rc_dev *dev)
{
static bool raw_init = false; /* raw decoders loaded? */
- static atomic_t devno = ATOMIC_INIT(0);
struct rc_map *rc_map;
const char *path;
int rc;
+ unsigned int i;
if (!dev || !dev->map_name)
return -EINVAL;
@@ -1161,6 +1166,26 @@ int rc_register_device(struct rc_dev *dev)
if (dev->close)
dev->input_dev->close = ir_close;
+ rc = mutex_lock_interruptible(&rc_dev_table_mutex);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < ARRAY_SIZE(rc_dev_table); i++) {
+ if (!rc_dev_table[i]) {
+ rc_dev_table[i] = dev;
+ break;
+ }
+ }
+
+ mutex_unlock(&rc_dev_table_mutex);
+
+ if (i >= ARRAY_SIZE(rc_dev_table))
+ return -ENFILE;
+
+ dev->minor = i;
+ dev_set_name(&dev->dev, "rc%u", dev->minor);
+ dev_set_drvdata(&dev->dev, dev);
+
/*
* Take the lock here, as the device sysfs node will appear
* when device_add() is called, which may trigger an ir-keytable udev
@@ -1170,9 +1195,6 @@ int rc_register_device(struct rc_dev *dev)
*/
mutex_lock(&dev->lock);
- dev->devno = (unsigned long)(atomic_inc_return(&devno) - 1);
- dev_set_name(&dev->dev, "rc%ld", dev->devno);
- dev_set_drvdata(&dev->dev, dev);
rc = device_add(&dev->dev);
if (rc)
goto out_unlock;
@@ -1231,8 +1253,8 @@ int rc_register_device(struct rc_dev *dev)
mutex_unlock(&dev->lock);
- IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n",
- dev->devno,
+ IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n",
+ dev->minor,
dev->driver_name ? dev->driver_name : "unknown",
rc_map->name ? rc_map->name : "unknown",
dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
@@ -1251,6 +1273,9 @@ out_dev:
device_del(&dev->dev);
out_unlock:
mutex_unlock(&dev->lock);
+ mutex_lock(&rc_dev_table_mutex);
+ rc_dev_table[dev->minor] = NULL;
+ mutex_unlock(&rc_dev_table_mutex);
return rc;
}
EXPORT_SYMBOL_GPL(rc_register_device);
@@ -1260,6 +1285,10 @@ void rc_unregister_device(struct rc_dev *dev)
if (!dev)
return;
+ mutex_lock(&rc_dev_table_mutex);
+ rc_dev_table[dev->minor] = NULL;
+ mutex_unlock(&rc_dev_table_mutex);
+
del_timer_sync(&dev->timer_keyup);
if (dev->driver_type == RC_DRIVER_IR_RAW)
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 0045292..1d4f5a0 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -63,7 +63,7 @@ struct rc_keymap_entry {
* @rc_map: current scan/key table
* @lock: used to ensure we've filled in all protocol details before
* anyone can call show_protocols or store_protocols
- * @devno: unique remote control device number
+ * @minor: unique minor remote control device number
* @raw: additional data for raw pulse/space devices
* @input_dev: the input child device used to communicate events to userspace
* @driver_type: specifies if protocol decoding is done in hardware or software
@@ -111,7 +111,7 @@ struct rc_dev {
const char *map_name;
struct rc_map rc_map;
struct mutex lock;
- unsigned long devno;
+ unsigned int minor;
struct ir_raw_event_ctrl *raw;
struct input_dev *input_dev;
enum rc_driver_type driver_type;
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 09/43] rc-core: add chardev
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (7 preceding siblings ...)
2012-05-23 9:42 ` [PATCH 08/43] rc-core: use a device table rather than an atomic number David Härdeman
@ 2012-05-23 9:42 ` David Härdeman
2012-05-23 9:42 ` [PATCH 10/43] rc-core: allow chardev to be read David Härdeman
` (34 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:42 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
This patch lays the groundwork for adding a rc-core chardev.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-main.c | 211 ++++++++++++++++++++++++++++++++++++++++----
include/media/rc-core.h | 6 +
2 files changed, 196 insertions(+), 21 deletions(-)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 8da7701..d7a50b6 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/slab.h>
+#include <linux/sched.h>
#include <linux/device.h>
#include <linux/module.h>
#include "rc-core-priv.h"
@@ -25,6 +26,7 @@
#define IR_TAB_MIN_SIZE 256
#define IR_TAB_MAX_SIZE 8192
#define RC_DEV_MAX 32
+#define RC_RX_BUFFER_SIZE 1024
/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
#define IR_KEYPRESS_TIMEOUT 250
@@ -34,9 +36,27 @@ static LIST_HEAD(rc_map_list);
static DEFINE_SPINLOCK(rc_map_lock);
/* Various bits and pieces to keep track of rc devices */
+static unsigned int rc_major;
static struct rc_dev *rc_dev_table[RC_DEV_MAX];
static DEFINE_MUTEX(rc_dev_table_mutex);
+/**
+ * struct rc_client - keeps track of processes which have opened a rc chardev
+ * @dev: the &struct rc_dev which is being controlled
+ * @rxlock: protects the rxfifo
+ * @rxfifo: stores rx events which can be read by the process
+ * @fasync: keeps track of the fasync queue
+ * @node: list of current clients for the rc device (protected by client_lock
+ * in &struct rc_dev)
+ */
+struct rc_client {
+ struct rc_dev *dev;
+ spinlock_t rxlock;
+ DECLARE_KFIFO(rxfifo, int, RC_RX_BUFFER_SIZE);
+ struct fasync_struct *fasync;
+ struct list_head node;
+};
+
static struct rc_map_list *seek_rc_map(const char *name)
{
struct rc_map_list *map = NULL;
@@ -1041,8 +1061,22 @@ out:
return ret;
}
+/**
+ * rc_dev_release() - release a &struct rc_dev
+ * @device: the &struct device which corresponds to the &struct rc_dev
+ *
+ * This function is called by the driver core when the refcount
+ * for the &device reaches zero.
+ */
static void rc_dev_release(struct device *device)
{
+ struct rc_dev *dev = to_rc_dev(device);
+
+ if (dev->input_dev)
+ input_free_device(dev->input_dev);
+
+ kfree(dev);
+ module_put(THIS_MODULE);
}
#define ADD_HOTPLUG_VAR(fmt, val...) \
@@ -1111,6 +1145,9 @@ struct rc_dev *rc_allocate_device(void)
dev->input_dev->setkeycode = ir_setkeycode;
input_set_drvdata(dev->input_dev, dev);
+ INIT_LIST_HEAD(&dev->client_list);
+ spin_lock_init(&dev->client_lock);
+
spin_lock_init(&dev->rc_map.lock);
spin_lock_init(&dev->keylock);
mutex_init(&dev->lock);
@@ -1125,18 +1162,18 @@ struct rc_dev *rc_allocate_device(void)
}
EXPORT_SYMBOL_GPL(rc_allocate_device);
+/**
+ * rc_free_device() - free an allocated struct rc_dev
+ * @dev: the &struct rc_dev to free
+ *
+ * This function is used by drivers to free a &struct rc_dev which has
+ * been allocated with rc_allocate_device(). It must not be used
+ * after rc_register_device() has been successfully called.
+ */
void rc_free_device(struct rc_dev *dev)
{
- if (!dev)
- return;
-
- if (dev->input_dev)
- input_free_device(dev->input_dev);
-
- put_device(&dev->dev);
-
- kfree(dev);
- module_put(THIS_MODULE);
+ if (dev)
+ put_device(&dev->dev);
}
EXPORT_SYMBOL_GPL(rc_free_device);
@@ -1183,6 +1220,7 @@ int rc_register_device(struct rc_dev *dev)
return -ENFILE;
dev->minor = i;
+ dev->dev.devt = MKDEV(rc_major, dev->minor);
dev_set_name(&dev->dev, "rc%u", dev->minor);
dev_set_drvdata(&dev->dev, dev);
@@ -1251,6 +1289,7 @@ int rc_register_device(struct rc_dev *dev)
goto out_raw;
}
+ dev->exist = true;
mutex_unlock(&dev->lock);
IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n",
@@ -1282,13 +1321,24 @@ EXPORT_SYMBOL_GPL(rc_register_device);
void rc_unregister_device(struct rc_dev *dev)
{
+ struct rc_client *client;
+
if (!dev)
return;
+ mutex_lock(&dev->lock);
+ dev->exist = false;
+ mutex_unlock(&dev->lock);
+
mutex_lock(&rc_dev_table_mutex);
rc_dev_table[dev->minor] = NULL;
mutex_unlock(&rc_dev_table_mutex);
+ spin_lock(&dev->client_lock);
+ list_for_each_entry(client, &dev->client_list, node)
+ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+ spin_unlock(&dev->client_lock);
+
del_timer_sync(&dev->timer_keyup);
if (dev->driver_type == RC_DRIVER_IR_RAW)
@@ -1301,34 +1351,153 @@ void rc_unregister_device(struct rc_dev *dev)
input_unregister_device(dev->input_dev);
dev->input_dev = NULL;
- device_del(&dev->dev);
-
- rc_free_device(dev);
+ device_unregister(&dev->dev);
}
EXPORT_SYMBOL_GPL(rc_unregister_device);
-/*
- * Init/exit code for the module. Basically, creates/removes /sys/class/rc
+/**
+ * rc_open() - allows userspace to open() a rc device file
+ * @inode: the &struct inode corresponding to the device file
+ * @file: the &struct file corresponding to the open() attempt
+ * @return: zero on success, or a negative error code
+ *
+ * This function (which implements open in &struct file_operations)
+ * allows userspace to open() a rc device file.
+ */
+static int rc_open(struct inode *inode, struct file *file)
+{
+ int err;
+ struct rc_dev *dev;
+ struct rc_client *client;
+
+ IR_dprintk(2, "Open attempt on %u\n", iminor(inode));
+
+ if (iminor(inode) >= RC_DEV_MAX)
+ return -ENODEV;
+
+ err = mutex_lock_interruptible(&rc_dev_table_mutex);
+ if (err)
+ return err;
+ dev = rc_dev_table[iminor(inode)];
+ if (dev && dev->exist)
+ get_device(&dev->dev);
+ else
+ dev = NULL;
+ mutex_unlock(&rc_dev_table_mutex);
+
+ if (!dev)
+ return -ENODEV;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ spin_lock_init(&client->rxlock);
+ INIT_KFIFO(client->rxfifo);
+ client->dev = dev;
+
+ spin_lock(&dev->client_lock);
+ list_add_tail_rcu(&client->node, &dev->client_list);
+ spin_unlock(&dev->client_lock);
+ synchronize_rcu();
+
+ file->private_data = client;
+ nonseekable_open(inode, file);
+
+ IR_dprintk(2, "Device %u opened\n", iminor(inode));
+ return 0;
+
+out:
+ put_device(&dev->dev);
+ return err;
+}
+
+/**
+ * rc_release() - allows userspace to close() a rc device file
+ * @inode: the &struct inode corresponding to the device file
+ * @file: the &struct file corresponding to the previous open()
+ * @return: zero on success, or a negative error code
+ *
+ * This function (which implements release in &struct file_operations)
+ * allows userspace to close() a rc device file.
*/
+static int rc_release(struct inode *inode, struct file *file)
+{
+ struct rc_client *client = file->private_data;
+ struct rc_dev *dev = client->dev;
+
+ spin_lock(&dev->client_lock);
+ list_del_rcu(&client->node);
+ spin_unlock(&dev->client_lock);
+ synchronize_rcu();
+ kfree(client);
+ put_device(&dev->dev);
+
+ IR_dprintk(2, "Device %u closed\n", iminor(inode));
+ return 0;
+}
+
+/**
+ * rc_fasync() - allows userspace to recieve asynchronous notifications
+ * @fd: the file descriptor corresponding to the opened rc device
+ * @file: the &struct file corresponding to the previous open()
+ * @on: whether notifications should be enabled or disabled
+ * @return: zero on success, or a negative error code
+ *
+ * This function (which implements fasync in &struct file_operations)
+ * allows userspace to receive asynchronous signal notifications
+ * when the state of a rc device file changes.
+ */
+static int rc_fasync(int fd, struct file *file, int on)
+{
+ struct rc_client *client = file->private_data;
+
+ return fasync_helper(fd, file, on, &client->fasync);
+}
+
+static const struct file_operations rc_fops = {
+ .owner = THIS_MODULE,
+ .open = rc_open,
+ .release = rc_release,
+ .fasync = rc_fasync,
+};
static int __init rc_core_init(void)
{
- int rc = class_register(&rc_class);
- if (rc) {
- printk(KERN_ERR "rc_core: unable to register rc class\n");
- return rc;
+ int ret;
+
+ ret = register_chrdev(0, "rc", &rc_fops);
+ if (ret < 0) {
+ printk(KERN_ERR "rc_core: failed to allocate char dev\n");
+ goto out;
}
- rc_map_register(&empty_map);
+ rc_major = ret;
+ IR_dprintk(1, "Allocated char dev: %u\n", rc_major);
+ ret = class_register(&rc_class);
+ if (ret < 0) {
+ printk(KERN_ERR "rc_core: unable to create rc class\n");
+ goto chrdev;
+ }
+
+ rc_map_register(&empty_map);
return 0;
+
+chrdev:
+ unregister_chrdev(rc_major, "rc");
+out:
+ return ret;
}
static void __exit rc_core_exit(void)
{
class_unregister(&rc_class);
- rc_map_unregister(&empty_map);
+ unregister_chrdev(rc_major, "rc");
+rc_map_unregister(&empty_map);
}
subsys_initcall(rc_core_init);
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 1d4f5a0..0cd414d 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -64,6 +64,9 @@ struct rc_keymap_entry {
* @lock: used to ensure we've filled in all protocol details before
* anyone can call show_protocols or store_protocols
* @minor: unique minor remote control device number
+ * @exist: used to determine if the device is still valid
+ * @client_list: list of clients (processes which have opened the rc chardev)
+ * @client_lock: protects client_list
* @raw: additional data for raw pulse/space devices
* @input_dev: the input child device used to communicate events to userspace
* @driver_type: specifies if protocol decoding is done in hardware or software
@@ -112,6 +115,9 @@ struct rc_dev {
struct rc_map rc_map;
struct mutex lock;
unsigned int minor;
+ bool exist;
+ struct list_head client_list;
+ spinlock_t client_lock;
struct ir_raw_event_ctrl *raw;
struct input_dev *input_dev;
enum rc_driver_type driver_type;
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 10/43] rc-core: allow chardev to be read
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (8 preceding siblings ...)
2012-05-23 9:42 ` [PATCH 09/43] rc-core: add chardev David Härdeman
@ 2012-05-23 9:42 ` David Härdeman
2012-05-23 9:42 ` [PATCH 11/43] mceusb: remove pointless kmalloc David Härdeman
` (33 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:42 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
This patch is the first step towards making the rc chardev usable by adding
read functionality.
Basically the implementation mimics what evdev does. Userspace applications can
open the rc device and read rc_event structs with data. Only some basic events
are supported for now but later patches will add further events.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-main.c | 134 +++++++++++++++++++++++++++++++++++++++++++-
include/media/rc-core.h | 31 ++++++++++
2 files changed, 163 insertions(+), 2 deletions(-)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index d7a50b6..ef8d358 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -20,6 +20,7 @@
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/module.h>
+#include <linux/poll.h>
#include "rc-core-priv.h"
/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
@@ -52,11 +53,66 @@ static DEFINE_MUTEX(rc_dev_table_mutex);
struct rc_client {
struct rc_dev *dev;
spinlock_t rxlock;
- DECLARE_KFIFO(rxfifo, int, RC_RX_BUFFER_SIZE);
+ DECLARE_KFIFO(rxfifo, struct rc_event, RC_RX_BUFFER_SIZE);
struct fasync_struct *fasync;
struct list_head node;
};
+/**
+ * rc_client_event() - passes an rc event to a specific client
+ * @client: the &struct rc_client for this client
+ * @type: the event type
+ * @code: the event code (type specific)
+ * @val: the event value (type and code specific)
+ *
+ * This function writes a &struct rc_event entry to the client kfifo
+ * for later reading from userspace.
+ */
+static void rc_client_event(struct rc_client *client, u16 type,
+ u16 code, u64 val)
+{
+ unsigned long flags;
+ struct rc_event event;
+
+ event.type = type;
+ event.code = code;
+ event.reserved = 0;
+ event.val = val;
+
+ spin_lock_irqsave(&client->rxlock, flags);
+ if (kfifo_is_full(&client->rxfifo)) {
+ kfifo_skip(&client->rxfifo);
+ event.type = RC_CORE;
+ event.code = RC_CORE_DROPPED;
+ event.val = 1;
+ }
+ kfifo_in(&client->rxfifo, &event, 1);
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
+ spin_unlock_irqrestore(&client->rxlock, flags);
+}
+
+/**
+ * rc_event() - sends an rc_event to all listeners
+ * @dev: the struct rc_dev of the device generating the event
+ * @type: the event type
+ * @code: the event code (type specific)
+ * @val: the event value (type and code specific)
+ *
+ * This function passes an rc event to all clients.
+ */
+void rc_event(struct rc_dev *dev, u16 type, u16 code, u64 val)
+{
+ struct rc_client *client;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(client, &dev->client_list, node)
+ rc_client_event(client, type, code, val);
+ rcu_read_unlock();
+
+ wake_up_interruptible(&dev->rxwait);
+}
+EXPORT_SYMBOL_GPL(rc_event);
+
static struct rc_map_list *seek_rc_map(const char *name)
{
struct rc_map_list *map = NULL;
@@ -719,6 +775,7 @@ void rc_repeat(struct rc_dev *dev)
input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
input_sync(dev->input_dev);
+ rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
if (!dev->keypressed)
goto out;
@@ -754,6 +811,9 @@ static void ir_do_keydown(struct rc_dev *dev, u16 protocol,
ir_do_keyup(dev, false);
input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
+ rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
+ rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
+ rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
if (new_event && keycode != KEY_RESERVED) {
/* Register a keypress */
@@ -1147,7 +1207,7 @@ struct rc_dev *rc_allocate_device(void)
INIT_LIST_HEAD(&dev->client_list);
spin_lock_init(&dev->client_lock);
-
+ init_waitqueue_head(&dev->rxwait);
spin_lock_init(&dev->rc_map.lock);
spin_lock_init(&dev->keylock);
mutex_init(&dev->lock);
@@ -1338,6 +1398,7 @@ void rc_unregister_device(struct rc_dev *dev)
list_for_each_entry(client, &dev->client_list, node)
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
spin_unlock(&dev->client_lock);
+ wake_up_interruptible_all(&dev->rxwait);
del_timer_sync(&dev->timer_keyup);
@@ -1441,6 +1502,73 @@ static int rc_release(struct inode *inode, struct file *file)
}
/**
+ * rc_read() - allows userspace to read rc events
+ * @file: the &struct file corresponding to the previous open()
+ * @buffer: the userspace buffer to read data to
+ * @count: the number of bytes to read
+ * @ppos: the file offset
+ * @return: the number of bytes read, or a negative error code
+ *
+ * This function (which implements read in &struct file_operations)
+ * allows userspace to read events from the rc device file.
+ */
+static ssize_t rc_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct rc_client *client = file->private_data;
+ struct rc_dev *dev = client->dev;
+ struct rc_event event;
+ int ret;
+
+ if (count < sizeof(event))
+ return -EINVAL;
+
+ if (kfifo_is_empty(&client->rxfifo) && dev->exist &&
+ (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
+
+ ret = wait_event_interruptible(dev->rxwait,
+ !kfifo_is_empty(&client->rxfifo) ||
+ !dev->exist);
+
+ if (ret)
+ return ret;
+
+ if (!dev->exist)
+ return -ENODEV;
+
+ for (ret = 0; ret + sizeof(event) <= count; ret += sizeof(event)) {
+ if (kfifo_out_spinlocked(&client->rxfifo, &event, 1,
+ &client->rxlock) != 1)
+ break;
+
+ if (copy_to_user(buffer + ret, &event, sizeof(event)))
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
+/**
+ * rc_poll() - allows userspace to poll rc device files
+ * @file: the &struct file corresponding to the previous open()
+ * @wait: used to keep track of processes waiting for poll events
+ * @return: a mask of poll events which have occurred
+ *
+ * This function (which implements poll in &struct file_operations)
+ * allows userspace to poll/select on the rc device file.
+ */
+static unsigned int rc_poll(struct file *file, poll_table *wait)
+{
+ struct rc_client *client = file->private_data;
+ struct rc_dev *dev = client->dev;
+
+ poll_wait(file, &dev->rxwait, wait);
+ return ((kfifo_is_empty(&client->rxfifo) ? 0 : (POLLIN | POLLRDNORM)) |
+ (dev->exist ? 0 : (POLLHUP | POLLERR)));
+}
+
+/**
* rc_fasync() - allows userspace to recieve asynchronous notifications
* @fd: the file descriptor corresponding to the opened rc device
* @file: the &struct file corresponding to the previous open()
@@ -1462,6 +1590,8 @@ static const struct file_operations rc_fops = {
.owner = THIS_MODULE,
.open = rc_open,
.release = rc_release,
+ .read = rc_read,
+ .poll = rc_poll,
.fasync = rc_fasync,
};
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 0cd414d..4f69aa9 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -67,6 +67,7 @@ struct rc_keymap_entry {
* @exist: used to determine if the device is still valid
* @client_list: list of clients (processes which have opened the rc chardev)
* @client_lock: protects client_list
+ * @rxwait: waitqueue for processes waiting for data to read
* @raw: additional data for raw pulse/space devices
* @input_dev: the input child device used to communicate events to userspace
* @driver_type: specifies if protocol decoding is done in hardware or software
@@ -118,6 +119,7 @@ struct rc_dev {
bool exist;
struct list_head client_list;
spinlock_t client_lock;
+ wait_queue_head_t rxwait;
struct ir_raw_event_ctrl *raw;
struct input_dev *input_dev;
enum rc_driver_type driver_type;
@@ -154,6 +156,34 @@ struct rc_dev {
#define to_rc_dev(d) container_of(d, struct rc_dev, dev)
+/* rc_event.type value */
+#define RC_DEBUG 0x0
+#define RC_CORE 0x1
+#define RC_KEY 0x2
+
+/* RC_CORE codes */
+#define RC_CORE_DROPPED 0x0
+
+/* RC_KEY codes */
+#define RC_KEY_REPEAT 0x0
+#define RC_KEY_PROTOCOL 0x1
+#define RC_KEY_SCANCODE 0x2
+#define RC_KEY_TOGGLE 0x3
+
+/**
+ * struct rc_event - used to communicate rc events to userspace
+ * @type: the event type
+ * @code: the event code (type specific)
+ * @reserved: zero for now
+ * @val: the event value (type and code specific)
+ */
+struct rc_event {
+ __u16 type;
+ __u16 code;
+ __u32 reserved;
+ __u64 val;
+} __packed;
+
/*
* From rc-main.c
* Those functions can be used on any type of Remote Controller. They
@@ -165,6 +195,7 @@ struct rc_dev *rc_allocate_device(void);
void rc_free_device(struct rc_dev *dev);
int rc_register_device(struct rc_dev *dev);
void rc_unregister_device(struct rc_dev *dev);
+void rc_event(struct rc_dev *dev, u16 type, u16 code, u64 val);
void rc_repeat(struct rc_dev *dev);
void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u64 scancode, u8 toggle);
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 11/43] mceusb: remove pointless kmalloc
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (9 preceding siblings ...)
2012-05-23 9:42 ` [PATCH 10/43] rc-core: allow chardev to be read David Härdeman
@ 2012-05-23 9:42 ` David Härdeman
2012-05-23 9:43 ` [PATCH 12/43] redrat: cleanup debug functions David Härdeman
` (32 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:42 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
The previous code allocated a char buffer of size MCE_CMDBUF_SIZE (384) by
kzalloc():ing sizeof(unsigned) * MCE_CMDBUF_SIZE bytes.
The buffer was therefore 4 * the necessary size.
Additionally, zeroing out the buffer is pointless.
Replace the allocated buffer with a stack buffer.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/mceusb.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index f0f053d..9f546be 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -785,11 +785,7 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
struct mceusb_dev *ir = dev->priv;
int i, ret = 0;
int cmdcount = 0;
- unsigned char *cmdbuf; /* MCE command buffer */
-
- cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL);
- if (!cmdbuf)
- return -ENOMEM;
+ unsigned char cmdbuf[MCE_CMDBUF_SIZE]; /* MCE command buffer */
/* MCE tx init header */
cmdbuf[cmdcount++] = MCE_CMD_PORT_IR;
@@ -841,7 +837,6 @@ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
mce_async_out(ir, cmdbuf, cmdcount);
out:
- kfree(cmdbuf);
return ret ? ret : count;
}
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 12/43] redrat: cleanup debug functions
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (10 preceding siblings ...)
2012-05-23 9:42 ` [PATCH 11/43] mceusb: remove pointless kmalloc David Härdeman
@ 2012-05-23 9:43 ` David Härdeman
2012-05-23 9:43 ` [PATCH 13/43] rc-core: use a kfifo for TX data David Härdeman
` (31 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
In preparation for the next patches I had to understand the redrat driver (not
an easy task).
In the process I noticed that the debug printing functions look quite
suspicious. This is a minimal attempt at cleaning them up (though more work
remains to be done).
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/redrat3.c | 40 +++++++++++++++++++++++-----------------
1 file changed, 23 insertions(+), 17 deletions(-)
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 13a679f..46137b8 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -252,25 +252,29 @@ static void redrat3_dump_signal_header(struct redrat3_signal_header *header)
pr_info(" * repeats: %u\n", header->no_repeats);
}
-static void redrat3_dump_signal_data(char *buffer, u16 len)
+static void redrat3_dump_signal_lens(u16 *buf, u8 n)
{
- int offset, i;
- char *data_vals;
+ unsigned i;
pr_info("%s:", __func__);
+ for (i = 0; i < n; i++) {
+ if (i % 10 == 0)
+ pr_cont("\n * ");
+ pr_cont("%02x ", buf[i]);
+ }
+ pr_cont("\n");
+}
- offset = RR3_TX_HEADER_OFFSET + RR3_HEADER_LENGTH
- + (RR3_DRIVER_MAXLENS * sizeof(u16));
-
- /* read RR3_DRIVER_MAXLENS from ctrl msg */
- data_vals = buffer + offset;
+static void redrat3_dump_signal_data(u8 *buf, u16 n)
+{
+ unsigned i;
- for (i = 0; i < len; i++) {
+ pr_info("%s:", __func__);
+ for (i = 0; i < n; i++) {
if (i % 10 == 0)
pr_cont("\n * ");
- pr_cont("%02x ", *data_vals++);
+ pr_cont("%02x ", buf[i]);
}
-
pr_cont("\n");
}
@@ -466,11 +470,6 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
header.no_repeats= sig_data[RR3_REPEATS_OFFSET];
- if (debug) {
- redrat3_dump_signal_header(&header);
- redrat3_dump_signal_data(sig_data, header.sig_size);
- }
-
mod_freq = redrat3_val_to_mod_freq(&header);
rr3_dbg(dev, "Got mod_freq of %u\n", mod_freq);
@@ -480,6 +479,12 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
data_vals = sig_data + RR3_HEADER_LENGTH +
(header.max_lengths * sizeof(u16));
+ if (debug) {
+ redrat3_dump_signal_header(&header);
+ redrat3_dump_signal_lens(len_vals, header.no_lengths);
+ redrat3_dump_signal_data(data_vals, header.sig_size);
+ }
+
/* process each rr3 encoded byte into an int */
for (i = 0; i < header.sig_size; i++) {
u16 val = len_vals[data_vals[i]];
@@ -1022,7 +1027,8 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
if (debug) {
redrat3_dump_signal_header(&header);
- redrat3_dump_signal_data(buffer, header.sig_size);
+ redrat3_dump_signal_lens(lengths_ptr, curlencheck);
+ redrat3_dump_signal_data(sigdata, count);
}
pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress);
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 13/43] rc-core: use a kfifo for TX data
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (11 preceding siblings ...)
2012-05-23 9:43 ` [PATCH 12/43] redrat: cleanup debug functions David Härdeman
@ 2012-05-23 9:43 ` David Härdeman
2012-05-23 9:43 ` [PATCH 14/43] rc-core: allow chardev to be written David Härdeman
` (30 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Using a per rc_dev TX kfifo for TX data simplifies the device drivers and lays
the ground for the next patch.
This means that every driver with TX capabilities need to be changed at the same
time.
It should be noted that the redrat TX functionality was almost completely
rewritten (to be less obfuscated and kmalloc-happy) and that the
TX functionality in nuvoton-cir.c is, and was, probably broken
before and after this patch.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/ene_ir.c | 47 +++----
drivers/media/rc/ene_ir.h | 9 -
drivers/media/rc/ir-lirc-codec.c | 57 +++------
drivers/media/rc/ite-cir.c | 17 +--
drivers/media/rc/mceusb.c | 77 +++++-------
drivers/media/rc/nuvoton-cir.c | 51 ++++----
drivers/media/rc/nuvoton-cir.h | 9 -
drivers/media/rc/rc-loopback.c | 21 +--
drivers/media/rc/rc-main.c | 10 ++
drivers/media/rc/redrat3.c | 245 +++++++++++++++-----------------------
drivers/media/rc/winbond-cir.c | 48 +++----
include/media/rc-core.h | 40 ++++--
12 files changed, 267 insertions(+), 364 deletions(-)
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index 10621dc..ec09646 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -604,7 +604,7 @@ static void ene_tx_enable(struct ene_device *dev)
static void ene_tx_disable(struct ene_device *dev)
{
ene_write_reg(dev, ENE_CIRCFG, dev->saved_conf1);
- dev->tx_buffer = NULL;
+ init_ir_raw_event(&dev->tx_event);
}
@@ -612,18 +612,11 @@ static void ene_tx_disable(struct ene_device *dev)
static void ene_tx_sample(struct ene_device *dev)
{
u8 raw_tx;
- u32 sample;
- bool pulse = dev->tx_sample_pulse;
-
- if (!dev->tx_buffer) {
- pr_warn("TX: BUG: attempt to transmit NULL buffer\n");
- return;
- }
/* Grab next TX sample */
- if (!dev->tx_sample) {
+ if (!dev->tx_event.duration) {
- if (dev->tx_pos == dev->tx_len) {
+ if (!kfifo_get(&dev->rdev->txfifo, &dev->tx_event)) {
if (!dev->tx_done) {
dbg("TX: no more data to send");
dev->tx_done = true;
@@ -636,21 +629,19 @@ static void ene_tx_sample(struct ene_device *dev)
}
}
- sample = dev->tx_buffer[dev->tx_pos++];
- dev->tx_sample_pulse = !dev->tx_sample_pulse;
-
- dev->tx_sample = DIV_ROUND_CLOSEST(sample, sample_period);
-
- if (!dev->tx_sample)
- dev->tx_sample = 1;
+ dev->tx_event.duration = DIV_ROUND_CLOSEST(dev->tx_event.duration,
+ US_TO_NS(sample_period));
+ if (!dev->tx_event.duration)
+ dev->tx_event.duration = 1;
}
- raw_tx = min(dev->tx_sample , (unsigned int)ENE_CIRRLC_OUT_MASK);
- dev->tx_sample -= raw_tx;
+ raw_tx = min_t(unsigned, dev->tx_event.duration, ENE_CIRRLC_OUT_MASK);
+ dev->tx_event.duration -= raw_tx;
dbg("TX: sample %8d (%s)", raw_tx * sample_period,
- pulse ? "pulse" : "space");
- if (pulse)
+ dev->tx_event.pulse ? "pulse" : "space");
+
+ if (dev->tx_event.pulse)
raw_tx |= ENE_CIRRLC_OUT_PULSE;
ene_write_reg(dev,
@@ -954,20 +945,16 @@ static void ene_set_idle(struct rc_dev *rdev, bool idle)
}
/* outside interface: transmit */
-static int ene_transmit(struct rc_dev *rdev, unsigned *buf, unsigned n)
+static int ene_transmit(struct rc_dev *rdev)
{
struct ene_device *dev = rdev->priv;
unsigned long flags;
- dev->tx_buffer = buf;
- dev->tx_len = n;
- dev->tx_pos = 0;
dev->tx_reg = 0;
- dev->tx_done = 0;
- dev->tx_sample = 0;
- dev->tx_sample_pulse = 0;
+ dev->tx_done = false;
- dbg("TX: %d samples", dev->tx_len);
+ init_ir_raw_event(&dev->tx_event);
+ dbg("TX: %d samples", kfifo_len(&rdev->txfifo));
spin_lock_irqsave(&dev->hw_lock, flags);
@@ -986,7 +973,7 @@ static int ene_transmit(struct rc_dev *rdev, unsigned *buf, unsigned n)
spin_unlock_irqrestore(&dev->hw_lock, flags);
} else
dbg("TX: done");
- return n;
+ return 0;
}
/* probe entry */
diff --git a/drivers/media/rc/ene_ir.h b/drivers/media/rc/ene_ir.h
index 6f978e8..975d67a 100644
--- a/drivers/media/rc/ene_ir.h
+++ b/drivers/media/rc/ene_ir.h
@@ -222,15 +222,10 @@ struct ene_device {
bool rx_fan_input_inuse; /* is fan input in use for rx*/
int tx_reg; /* current reg used for TX */
u8 saved_conf1; /* saved FEC0 reg */
- unsigned int tx_sample; /* current sample for TX */
- bool tx_sample_pulse; /* current sample is pulse */
/* TX buffer */
- unsigned *tx_buffer; /* input samples buffer*/
- int tx_pos; /* position in that buffer */
- int tx_len; /* current len of tx buffer */
- int tx_done; /* done transmitting */
- /* one more sample pending*/
+ struct ir_raw_event tx_event; /* current sample for TX */
+ bool tx_done; /* done transmitting */
struct completion tx_complete; /* TX completion */
struct timer_list tx_sim_timer;
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 1490a8b..795cbdf 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -102,52 +102,41 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
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_codec *lirc = lirc_get_pdata(file);
struct rc_dev *dev;
- unsigned int *txbuf; /* buffer with values to transmit */
- ssize_t ret = 0;
- size_t count;
- ktime_t start;
+ ktime_t start = ktime_get();
+ u32 value;
+ ssize_t ret;
s64 towait;
unsigned int duration = 0; /* signal duration in us */
- int i;
-
- start = ktime_get();
+ DEFINE_IR_RAW_EVENT(event);
+ bool pulse = true;
- lirc = lirc_get_pdata(file);
- if (!lirc)
+ if (!lirc || !lirc->dev)
return -EFAULT;
- if (n < sizeof(unsigned) || n % sizeof(unsigned))
- return -EINVAL;
+ dev = lirc->dev;
+ if (!dev->tx_ir)
+ return -ENOSYS;
- count = n / sizeof(unsigned);
- if (count > LIRCBUF_SIZE || count % 2 == 0)
+ if (n % sizeof(u32) || ((n / sizeof(u32)) % 2) == 0)
return -EINVAL;
- txbuf = memdup_user(buf, n);
- if (IS_ERR(txbuf))
- return PTR_ERR(txbuf);
+ for (ret = 0; ret + sizeof(u32) <= n; ret += sizeof(u32)) {
+ if (copy_from_user(&value, buf + ret, sizeof(u32)))
+ return -EFAULT;
- dev = lirc->dev;
- if (!dev) {
- ret = -EFAULT;
- goto out;
- }
+ event.pulse = pulse;
+ event.duration = US_TO_NS(value);
+ if (kfifo_in_spinlocked(&dev->txfifo, &event, 1, &dev->txlock)
+ != 1)
+ break;
- if (!dev->tx_ir) {
- ret = -ENOSYS;
- goto out;
+ pulse = !pulse;
+ duration += value;
}
- ret = dev->tx_ir(dev, txbuf, (u32)count);
- if (ret < 0)
- goto out;
-
- for (i = 0; i < ret; i++)
- duration += txbuf[i];
-
- ret *= sizeof(unsigned int);
+ dev->tx_ir(dev);
/*
* The lircd gap calculation expects the write function to
@@ -160,8 +149,6 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
schedule_timeout(usecs_to_jiffies(towait));
}
-out:
- kfree(txbuf);
return ret;
}
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 494801e..5abb7c3 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -382,16 +382,15 @@ static int ite_set_tx_duty_cycle(struct rc_dev *rcdev, u32 duty_cycle)
/* transmit out IR pulses; what you get here is a batch of alternating
* pulse/space/pulse/space lengths that we should write out completely through
* the FIFO, blocking on a full FIFO */
-static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n)
+static int ite_tx_ir(struct rc_dev *rcdev)
{
unsigned long flags;
struct ite_dev *dev = rcdev->priv;
- bool is_pulse = false;
int remaining_us, fifo_avail, fifo_remaining, last_idx = 0;
int max_rle_us, next_rle_us;
- int ret = n;
u8 last_sent[ITE_TX_FIFO_LEN];
u8 val;
+ DEFINE_IR_RAW_EVENT(event);
ite_dbg("%s called", __func__);
@@ -421,14 +420,12 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n)
fifo_avail =
ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev);
- while (n > 0 && dev->in_use) {
+ while (kfifo_get(&rcdev->txfifo, &event) && dev->in_use) {
/* transmit the next sample */
- is_pulse = !is_pulse;
- remaining_us = *(txbuf++);
- n--;
+ remaining_us = event.duration;
ite_dbg("%s: %ld",
- ((is_pulse) ? "pulse" : "space"),
+ (event.pulse ? "pulse" : "space"),
(long int)
remaining_us);
@@ -453,7 +450,7 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n)
val = (val - 1) & ITE_TX_RLE_MASK;
/* take into account pulse/space prefix */
- if (is_pulse)
+ if (event.pulse)
val |= ITE_TX_PULSE;
else
@@ -529,7 +526,7 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n)
spin_unlock_irqrestore(&dev->lock, flags);
- return ret;
+ return 0;
}
/* idle the receiver if needed */
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 9f546be..c60ac4e 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -780,64 +780,51 @@ static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size)
}
/* Send data out the IR blaster port(s) */
-static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+static int mceusb_tx_ir(struct rc_dev *dev)
{
struct mceusb_dev *ir = dev->priv;
- int i, ret = 0;
- int cmdcount = 0;
- unsigned char cmdbuf[MCE_CMDBUF_SIZE]; /* MCE command buffer */
+ unsigned tmp, i = 0;
+ unsigned char buf[MCE_CMDBUF_SIZE]; /* MCE command buffer */
+ DEFINE_IR_RAW_EVENT(event);
/* MCE tx init header */
- cmdbuf[cmdcount++] = MCE_CMD_PORT_IR;
- cmdbuf[cmdcount++] = MCE_CMD_SETIRTXPORTS;
- cmdbuf[cmdcount++] = ir->tx_mask;
-
- /* Generate mce packet data */
- for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
- txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
-
- do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
-
- /* Insert mce packet header every 4th entry */
- if ((cmdcount < MCE_CMDBUF_SIZE) &&
- (cmdcount - MCE_TX_HEADER_LENGTH) %
- MCE_CODE_LENGTH == 0)
- cmdbuf[cmdcount++] = MCE_IRDATA_HEADER;
-
- /* Insert mce packet data */
- if (cmdcount < MCE_CMDBUF_SIZE)
- cmdbuf[cmdcount++] =
- (txbuf[i] < MCE_PULSE_BIT ?
- txbuf[i] : MCE_MAX_PULSE_LENGTH) |
- (i & 1 ? 0x00 : MCE_PULSE_BIT);
- else {
- ret = -EINVAL;
- goto out;
- }
+ buf[i++] = MCE_CMD_PORT_IR;
+ buf[i++] = MCE_CMD_SETIRTXPORTS;
+ buf[i++] = ir->tx_mask;
- } while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) &&
- (txbuf[i] -= MCE_MAX_PULSE_LENGTH));
- }
+ while (kfifo_get(&dev->txfifo, &event)) {
+ tmp = event.duration / US_TO_NS(MCE_TIME_UNIT);
- /* Fix packet length in last header */
- cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] =
- MCE_COMMAND_IRDATA + (cmdcount - MCE_TX_HEADER_LENGTH) %
- MCE_CODE_LENGTH - 1;
+ /* Split event into pulses/spaces <= 127 * 50us = 6.35ms */
+ while (tmp > 0 && i < (MCE_CMDBUF_SIZE - 1)) {
- /* Check if we have room for the empty packet at the end */
- if (cmdcount >= MCE_CMDBUF_SIZE) {
- ret = -EINVAL;
- goto out;
+ /* Insert packet header before every 4 bytes */
+ if ((i - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH == 0)
+ buf[i++] = MCE_IRDATA_HEADER;
+
+ buf[i] = min_t(unsigned, tmp, MCE_MAX_PULSE_LENGTH);
+ tmp -= buf[i];
+ buf[i++] |= event.pulse ? MCE_PULSE_BIT : 0x00;
+ }
+
+ /* See if command buffer is full */
+ if (tmp > 0 || i >= MCE_CMDBUF_SIZE) {
+ kfifo_reset_out(&dev->txfifo);
+ return -EINVAL;
+ }
}
+ /* Fix packet length in last header */
+ tmp = ((i - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH);
+ buf[i - tmp] -= (MCE_CODE_LENGTH - tmp);
+
/* All mce commands end with an empty packet (0x80) */
- cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER;
+ buf[i++] = MCE_IRDATA_TRAILER;
/* Transmit the command to the mce device */
- mce_async_out(ir, cmdbuf, cmdcount);
+ mce_async_out(ir, buf, i);
-out:
- return ret ? ret : count;
+ return 0;
}
/* Sets active IR outputs -- mce devices typically have two */
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index f4ce071..447f0d0 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -546,21 +546,16 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
* number may larger than TXFCONT (0xff). So in interrupt_handler, it has to
* set TXFCONT as 0xff, until buf_count less than 0xff.
*/
-static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n)
+static int nvt_tx_ir(struct rc_dev *dev)
{
struct nvt_dev *nvt = dev->priv;
unsigned long flags;
unsigned int i;
u8 iren;
- int ret;
spin_lock_irqsave(&nvt->tx.lock, flags);
- ret = min((unsigned)(TX_BUF_LEN / sizeof(unsigned)), n);
- nvt->tx.buf_count = (ret * sizeof(unsigned));
-
- memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count);
-
+ nvt->tx.buf_count = 0;
nvt->tx.cur_buf_num = 0;
/* save currently enabled interrupts */
@@ -589,7 +584,7 @@ static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n)
/* restore enabled interrupts to prior state */
nvt_cir_reg_write(nvt, iren, CIR_IREN);
- return ret;
+ return 0;
}
/* dump contents of the last rx buffer we got from the hw rx fifo */
@@ -826,27 +821,37 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
if (status & CIR_IRSTS_TE)
nvt_clear_tx_fifo(nvt);
+ /*
+ * FIXME: The TX code is quite unlikely to do the right thing as it
+ * merely sends unsigned ints with host-specific endianness to
+ * the hardware without any hints of pulse/space, etc.
+ */
if (status & CIR_IRSTS_TTR) {
- unsigned int pos, count;
- u8 tmp;
-
spin_lock_irqsave(&nvt->tx.lock, flags);
- pos = nvt->tx.cur_buf_num;
- count = nvt->tx.buf_count;
-
- /* Write data into the hardware tx fifo while pos < count */
- if (pos < count) {
- nvt_cir_reg_write(nvt, nvt->tx.buf[pos], CIR_STXFIFO);
- nvt->tx.cur_buf_num++;
- /* Disable TX FIFO Trigger Level Reach (TTR) interrupt */
- } else {
- tmp = nvt_cir_reg_read(nvt, CIR_IREN);
- nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN);
+ /* Any data in tx buffer? */
+ if (nvt->tx.cur_buf_num >= nvt->tx.buf_count) {
+ DEFINE_IR_RAW_EVENT(event);
+ if (!kfifo_get(&nvt->rdev->txfifo, &event)) {
+ /* No more data, disable TTR interrupt */
+ u8 tmp = nvt_cir_reg_read(nvt, CIR_IREN);
+ nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN);
+ } else {
+ unsigned sample = event.duration / 1000;
+ nvt->tx.buf_count = sizeof(sample);
+ nvt->tx.cur_buf_num = 0;
+ memcpy(nvt->tx.buf, &sample, sizeof(sample));
+ }
}
- spin_unlock_irqrestore(&nvt->tx.lock, flags);
+ /* Write data into the hardware tx fifo if we have any */
+ if (nvt->tx.cur_buf_num < nvt->tx.buf_count) {
+ nvt_cir_reg_write(nvt,
+ nvt->tx.buf[nvt->tx.cur_buf_num++],
+ CIR_STXFIFO);
+ }
+ spin_unlock_irqrestore(&nvt->tx.lock, flags);
}
if (status & CIR_IRSTS_TFU) {
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index 0d5e087..4477439 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -54,15 +54,8 @@ static int debug;
KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
-/*
- * Original lirc driver said min value of 76, and recommended value of 256
- * for the buffer length, but then used 2048. Never mind that the size of the
- * RX FIFO is 32 bytes... So I'm using 32 for RX and 256 for TX atm, but I'm
- * not sure if maybe that TX value is off by a factor of 8 (bits vs. bytes),
- * and I don't have TX-capable hardware to test/debug on...
- */
-#define TX_BUF_LEN 256
#define RX_BUF_LEN 32
+#define TX_BUF_LEN sizeof(unsigned)
struct nvt_dev {
struct pnp_dev *pdev;
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 53d0282..b6a2e58 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -101,17 +101,17 @@ static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max)
return 0;
}
-static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
+static int loop_tx_ir(struct rc_dev *dev)
{
struct loopback_dev *lodev = dev->priv;
u32 rxmask;
- unsigned i;
DEFINE_IR_RAW_EVENT(rawir);
if (lodev->txcarrier < lodev->rxcarriermin ||
lodev->txcarrier > lodev->rxcarriermax) {
dprintk("ignoring tx, carrier out of range\n");
- goto out;
+ kfifo_reset_out(&dev->txfifo);
+ return 0;
}
if (lodev->learning)
@@ -121,25 +121,22 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
if (!(rxmask & lodev->txmask)) {
dprintk("ignoring tx, rx mask mismatch\n");
- goto out;
+ kfifo_reset_out(&dev->txfifo);
+ return 0;
}
- for (i = 0; i < count; i++) {
- rawir.pulse = i % 2 ? false : true;
- rawir.duration = txbuf[i] * 1000;
- if (rawir.duration)
- ir_raw_event_store_with_filter(dev, &rawir);
- }
+ while (kfifo_get(&dev->txfifo, &rawir))
+ ir_raw_event_store_with_filter(dev, &rawir);
/* Fake a silence long enough to cause us to go idle */
+ init_ir_raw_event(&rawir);
rawir.pulse = false;
rawir.duration = dev->timeout;
ir_raw_event_store_with_filter(dev, &rawir);
ir_raw_event_handle(dev);
-out:
- return count;
+ return 0;
}
static void loop_set_idle(struct rc_dev *dev, bool enable)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index ef8d358..80d6dac 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1135,6 +1135,7 @@ static void rc_dev_release(struct device *device)
if (dev->input_dev)
input_free_device(dev->input_dev);
+ kfifo_free(&dev->txfifo);
kfree(dev);
module_put(THIS_MODULE);
}
@@ -1207,6 +1208,8 @@ struct rc_dev *rc_allocate_device(void)
INIT_LIST_HEAD(&dev->client_list);
spin_lock_init(&dev->client_lock);
+ INIT_KFIFO(dev->txfifo);
+ spin_lock_init(&dev->txlock);
init_waitqueue_head(&dev->rxwait);
spin_lock_init(&dev->rc_map.lock);
spin_lock_init(&dev->keylock);
@@ -1284,6 +1287,12 @@ int rc_register_device(struct rc_dev *dev)
dev_set_name(&dev->dev, "rc%u", dev->minor);
dev_set_drvdata(&dev->dev, dev);
+ if (dev->tx_ir) {
+ rc = kfifo_alloc(&dev->txfifo, RC_TX_KFIFO_SIZE, GFP_KERNEL);
+ if (rc)
+ goto out_minor;
+ }
+
/*
* Take the lock here, as the device sysfs node will appear
* when device_add() is called, which may trigger an ir-keytable udev
@@ -1372,6 +1381,7 @@ out_dev:
device_del(&dev->dev);
out_unlock:
mutex_unlock(&dev->lock);
+out_minor:
mutex_lock(&rc_dev_table_mutex);
rc_dev_table[dev->minor] = NULL;
mutex_unlock(&rc_dev_table_mutex);
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 46137b8..5eefb0b 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -223,7 +223,7 @@ struct redrat3_dev {
char phys[64];
};
-/* All incoming data buffers adhere to a very specific data format */
+/* All incoming/outgoing data buffers have the following header */
struct redrat3_signal_header {
u16 length; /* Length of data being transferred */
u16 transfer_type; /* Type of data transferred */
@@ -235,8 +235,19 @@ struct redrat3_signal_header {
u16 max_sig_size; /* Max no. of values in signal data array */
u16 sig_size; /* Acuto no. of values in signal data array */
u8 no_repeats; /* No. of repeats of repeat signal section */
- /* Here forward is the lengths and signal data */
-};
+} __packed;
+
+/*
+ * Data is sent by using a packet with a header followed by two arrays.
+ * - one with sample sizes (big-endian u16)
+ * - one with array index values (referring to the first array) which represent
+ * alternating pulse/space samples
+ */
+struct redrat3_tx_data {
+ struct redrat3_signal_header header;
+ u16 lens[RR3_DRIVER_MAXLENS];
+ u8 samples[RR3_MAX_SIG_SIZE];
+} __packed;
static void redrat3_dump_signal_header(struct redrat3_signal_header *header)
{
@@ -370,40 +381,26 @@ static u32 redrat3_val_to_mod_freq(struct redrat3_signal_header *ph)
return mod_freq;
}
-/* this function scales down the figures for the same result... */
-static u32 redrat3_len_to_us(u32 length)
-{
- u32 biglen = length * 1000;
- u32 divisor = (RR3_CLK_CONV_FACTOR) / 1000;
- u32 result = (u32) (biglen / divisor);
-
- /* don't allow zero lengths to go back, breaks lirc */
- return result ? result : 1;
-}
-
/*
- * convert us back into redrat3 lengths
+ * Functions to convert between microseconds (u32) and redrat3 lengths (u16)
*
- * length * 1000 length * 1000000
- * ------------- = ---------------- = micro
- * rr3clk / 1000 rr3clk
-
- * 6 * 2 4 * 3 micro * rr3clk micro * rr3clk / 1000
- * ----- = 4 ----- = 6 -------------- = len ---------------------
- * 3 2 1000000 1000
+ * 1000000 rr3clk
+ * ------- * len = us => ------- * us = len
+ * rr3clk 1000000
+ *
+ * Zero samples are avoided as they confuse lirc.
*/
-static u32 redrat3_us_to_len(u32 microsec)
+static inline u32 redrat3_len_to_us(u16 length)
{
- u32 result;
- u32 divisor;
-
- microsec &= IR_MAX_DURATION;
- divisor = (RR3_CLK_CONV_FACTOR / 1000);
- result = (u32)(microsec * divisor) / 1000;
-
- /* don't allow zero lengths to go back, breaks lirc */
- return result ? result : 1;
+ return max((u32)length / (RR3_CLK_CONV_FACTOR / (1000000)), (u32)1);
+}
+#define RR_MAX_DURATION (redrat3_len_to_us((u16)(~0)))
+static inline u16 redrat3_us_to_len(u32 microsec)
+{
+ return max(max(microsec, RR_MAX_DURATION) *
+ (RR3_CLK_CONV_FACTOR / (1000000)),
+ (u32)1);
}
/* timer callback to send reset event */
@@ -900,22 +897,21 @@ static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier)
return carrier;
}
-static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
- unsigned count)
+/*
+ * Transmit IR data
+ *
+ * See the description of struct redrat3_tx_data above.
+ */
+static int redrat3_transmit_ir(struct rc_dev *rcdev)
{
struct redrat3_dev *rr3 = rcdev->priv;
struct device *dev = rr3->dev;
- struct redrat3_signal_header header;
- int i, j, ret, ret_len, offset;
- int lencheck, cur_sample_len, pipe;
- char *buffer = NULL, *sigdata = NULL;
- int *sample_lens = NULL;
- u32 tmpi;
- u16 tmps;
- u8 *datap;
- u8 curlencheck = 0;
- u16 *lengths_ptr;
- int sendbuf_len;
+ DEFINE_IR_RAW_EVENT(event);
+ struct redrat3_tx_data tx;
+ unsigned nlens = 0, nsamples = 0, i;
+ int txlen, actual_len;
+ int ret;
+ u16 sample;
rr3_ftr(dev, "Entering %s\n", __func__);
@@ -924,138 +920,87 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
return -EAGAIN;
}
- if (count > (RR3_DRIVER_MAXLENS * 2))
- return -EINVAL;
-
/* rr3 will disable rc detector on transmit */
rr3->det_enabled = false;
rr3->transmitting = true;
- sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL);
- if (!sample_lens) {
- ret = -ENOMEM;
- goto out;
- }
+ while (kfifo_get(&rcdev->txfifo, &event)) {
+ /* Convert duration to RR format */
+ sample = redrat3_us_to_len(event.duration / 1000);
- for (i = 0; i < count; i++) {
- for (lencheck = 0; lencheck < curlencheck; lencheck++) {
- cur_sample_len = redrat3_us_to_len(txbuf[i]);
- if (sample_lens[lencheck] == cur_sample_len)
+ /* See if we already have the same sample size stored */
+ for (i = 0; i < nlens; i++)
+ if (tx.lens[i] == sample)
break;
- }
- if (lencheck == curlencheck) {
- cur_sample_len = redrat3_us_to_len(txbuf[i]);
- rr3_dbg(dev, "txbuf[%d]=%u, pos %d, enc %u\n",
- i, txbuf[i], curlencheck, cur_sample_len);
- if (curlencheck < 255) {
- /* now convert the value to a proper
- * rr3 value.. */
- sample_lens[curlencheck] = cur_sample_len;
- curlencheck++;
- } else {
- dev_err(dev, "signal too long\n");
+
+ if (i >= nlens) {
+ /* Nope */
+ if (nlens >= ARRAY_SIZE(tx.lens)) {
+ dev_err(dev, "signal too long (lens)\n");
ret = -EINVAL;
goto out;
}
+ rr3_dbg(dev, "lens[%u] = %u\n", nlens, sample);
+ tx.lens[nlens++] = sample;
}
- }
- sigdata = kzalloc((count + RR3_TX_TRAILER_LEN), GFP_KERNEL);
- if (!sigdata) {
- ret = -ENOMEM;
- goto out;
- }
-
- sigdata[count] = RR3_END_OF_SIGNAL;
- sigdata[count + 1] = RR3_END_OF_SIGNAL;
- for (i = 0; i < count; i++) {
- for (j = 0; j < curlencheck; j++) {
- if (sample_lens[j] == redrat3_us_to_len(txbuf[i]))
- sigdata[i] = j;
+ /* And store the sample */
+ if (nsamples >= ARRAY_SIZE(tx.samples) - RR3_TX_TRAILER_LEN) {
+ dev_err(dev, "signal too long (samples)\n");
+ ret = -EINVAL;
+ goto out;
}
+ tx.samples[nsamples++] = i;
}
- offset = RR3_TX_HEADER_OFFSET;
- sendbuf_len = RR3_HEADER_LENGTH + (sizeof(u16) * RR3_DRIVER_MAXLENS)
- + count + RR3_TX_TRAILER_LEN + offset;
+ for (i = 0; i < nlens; i++)
+ cpu_to_be16s(&tx.lens[i]);
+
+ /* Add TX trailer */
+ tx.samples[nsamples++] = RR3_END_OF_SIGNAL;
+ tx.samples[nsamples++] = RR3_END_OF_SIGNAL;
+
+ /* Fill in our packet header */
+ txlen = sizeof(tx) - (RR3_MAX_SIG_SIZE - nsamples);
+ tx.header.length = cpu_to_be16(txlen - RR3_TX_HEADER_OFFSET);
+ tx.header.transfer_type = cpu_to_be16(RR3_MOD_SIGNAL_OUT);
+ tx.header.pause = cpu_to_be32(redrat3_len_to_us(100));
+ tx.header.mod_freq_count = cpu_to_be16(mod_freq_to_val(rr3->carrier));
+ tx.header.no_periods = cpu_to_be16(0); /* n/a to transmit */
+ tx.header.max_lengths = RR3_DRIVER_MAXLENS; /* u8 */
+ tx.header.no_lengths = nlens; /* u8 */
+ tx.header.max_sig_size = cpu_to_be16(RR3_MAX_SIG_SIZE);
+ tx.header.sig_size = cpu_to_be16(nsamples);
+ /* We currently rely on repeat handling in user-space */
+ tx.header.no_repeats = 0; /* u8 */
- buffer = kzalloc(sendbuf_len, GFP_KERNEL);
- if (!buffer) {
- ret = -ENOMEM;
- goto out;
+ if (debug) {
+ redrat3_dump_signal_header(&tx.header);
+ redrat3_dump_signal_lens(tx.lens, nlens);
+ redrat3_dump_signal_data(tx.samples, nsamples);
}
- /* fill in our packet header */
- header.length = sendbuf_len - offset;
- header.transfer_type = RR3_MOD_SIGNAL_OUT;
- header.pause = redrat3_len_to_us(100);
- header.mod_freq_count = mod_freq_to_val(rr3->carrier);
- header.no_periods = 0; /* n/a to transmit */
- header.max_lengths = RR3_DRIVER_MAXLENS;
- header.no_lengths = curlencheck;
- header.max_sig_size = RR3_MAX_SIG_SIZE;
- header.sig_size = count + RR3_TX_TRAILER_LEN;
- /* we currently rely on repeat handling in the IR encoding source */
- header.no_repeats = 0;
-
- tmps = cpu_to_be16(header.length);
- memcpy(buffer, &tmps, 2);
-
- tmps = cpu_to_be16(header.transfer_type);
- memcpy(buffer + 2, &tmps, 2);
-
- tmpi = cpu_to_be32(header.pause);
- memcpy(buffer + offset, &tmpi, sizeof(tmpi));
-
- tmps = cpu_to_be16(header.mod_freq_count);
- memcpy(buffer + offset + RR3_FREQ_COUNT_OFFSET, &tmps, 2);
-
- buffer[offset + RR3_NUM_LENGTHS_OFFSET] = header.no_lengths;
-
- tmps = cpu_to_be16(header.sig_size);
- memcpy(buffer + offset + RR3_NUM_SIGS_OFFSET, &tmps, 2);
-
- buffer[offset + RR3_REPEATS_OFFSET] = header.no_repeats;
-
- lengths_ptr = (u16 *)(buffer + offset + RR3_HEADER_LENGTH);
- for (i = 0; i < curlencheck; ++i)
- lengths_ptr[i] = cpu_to_be16(sample_lens[i]);
-
- datap = (u8 *)(buffer + offset + RR3_HEADER_LENGTH +
- (sizeof(u16) * RR3_DRIVER_MAXLENS));
- memcpy(datap, sigdata, (count + RR3_TX_TRAILER_LEN));
-
- if (debug) {
- redrat3_dump_signal_header(&header);
- redrat3_dump_signal_lens(lengths_ptr, curlencheck);
- redrat3_dump_signal_data(sigdata, count);
+ ret = usb_bulk_msg(rr3->udev,
+ usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress),
+ &tx, txlen, &actual_len, 10 * HZ);
+ if (ret < 0) {
+ dev_err(dev, "Error: bulk msg send failed, rc %d\n", ret);
+ goto out;
}
- pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress);
- tmps = usb_bulk_msg(rr3->udev, pipe, buffer,
- sendbuf_len, &ret_len, 10 * HZ);
- rr3_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, tmps);
+ rr3_dbg(dev, "sent usb bulk msg - %i bytes\n", actual_len);
- /* now tell the hardware to transmit what we sent it */
- pipe = usb_rcvctrlpipe(rr3->udev, 0);
- ret = usb_control_msg(rr3->udev, pipe, RR3_TX_SEND_SIGNAL,
+ ret = usb_control_msg(rr3->udev,
+ usb_rcvctrlpipe(rr3->udev, 0),
+ RR3_TX_SEND_SIGNAL,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0, 0, buffer, 2, HZ * 10);
-
+ 0, 0, &tx, 2, HZ * 10);
if (ret < 0)
dev_err(dev, "Error: control msg send failed, rc %d\n", ret);
- else
- ret = count;
out:
- kfree(sample_lens);
- kfree(buffer);
- kfree(sigdata);
-
rr3->transmitting = false;
- /* rr3 re-enables rc detector because it was enabled before */
rr3->det_enabled = true;
-
return ret;
}
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 342c2c8..207410c 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -213,9 +213,7 @@ struct wbcir_data {
/* TX state */
enum wbcir_txstate txstate;
struct led_trigger *txtrigger;
- u32 txlen;
- u32 txoff;
- u32 *txbuf;
+ struct ir_raw_event txevent;
wait_queue_head_t txwaitq;
u8 txmask;
u32 txcarrier;
@@ -379,7 +377,7 @@ wbcir_irq_tx(struct wbcir_data *data)
u8 bytes[16];
u8 byte;
- if (!data->txbuf)
+ if (kfifo_is_empty(&data->dev->txfifo))
return;
switch (data->txstate) {
@@ -404,21 +402,23 @@ wbcir_irq_tx(struct wbcir_data *data)
* Y = space (1) or pulse (0)
* X = duration, encoded as (X + 1) * 10us (i.e 10 to 1280 us)
*/
- for (used = 0; used < space && data->txoff != data->txlen; used++) {
- if (data->txbuf[data->txoff] == 0) {
- data->txoff++;
- continue;
+ for (used = 0; used < space; used++) {
+ while (data->txevent.duration == 0) {
+ if (!kfifo_get(&data->dev->txfifo, &data->txevent))
+ break;
+ /* Convert duration to multiples of 10us */
+ data->txevent.duration =
+ DIV_ROUND_CLOSEST(data->txevent.duration,
+ 10 * 1000);
}
- byte = min((u32)0x80, data->txbuf[data->txoff]);
- data->txbuf[data->txoff] -= byte;
+
+ byte = min_t(u32, 0x80, data->txevent.duration);
+ data->txevent.duration -= byte;
byte--;
- byte |= (data->txoff % 2 ? 0x80 : 0x00); /* pulse/space */
+ byte |= data->txevent.pulse ? 0x80 : 0x00;
bytes[used] = byte;
}
- while (data->txbuf[data->txoff] == 0 && data->txoff != data->txlen)
- data->txoff++;
-
if (used == 0) {
/* Finished */
if (data->txstate == WBCIR_TXSTATE_ERROR)
@@ -429,7 +429,8 @@ wbcir_irq_tx(struct wbcir_data *data)
wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR);
led_trigger_event(data->txtrigger, LED_OFF);
wake_up(&data->txwaitq);
- } else if (data->txoff == data->txlen) {
+ } else if (data->txevent.duration == 0 &&
+ kfifo_is_empty(&data->dev->txfifo)) {
/* At the end of transmission, tell the hw before last byte */
outsb(data->sbase + WBCIR_REG_SP3_TXDATA, bytes, used - 1);
outb(WBCIR_TX_EOT, data->sbase + WBCIR_REG_SP3_ASCR);
@@ -579,11 +580,11 @@ wbcir_txmask(struct rc_dev *dev, u32 mask)
}
static int
-wbcir_tx(struct rc_dev *dev, unsigned *buf, unsigned count)
+wbcir_tx(struct rc_dev *dev)
{
struct wbcir_data *data = dev->priv;
- unsigned i;
unsigned long flags;
+ int ret = 0;
/* Not sure if this is possible, but better safe than sorry */
spin_lock_irqsave(&data->spinlock, flags);
@@ -592,14 +593,8 @@ wbcir_tx(struct rc_dev *dev, unsigned *buf, unsigned count)
return -EBUSY;
}
- /* Convert values to multiples of 10us */
- for (i = 0; i < count; i++)
- buf[i] = DIV_ROUND_CLOSEST(buf[i], 10);
-
/* Fill the TX fifo once, the irq handler will do the rest */
- data->txbuf = buf;
- data->txlen = count;
- data->txoff = 0;
+ init_ir_raw_event(&data->txevent);
wbcir_irq_tx(data);
/* Wait for the TX to complete */
@@ -611,12 +606,11 @@ wbcir_tx(struct rc_dev *dev, unsigned *buf, unsigned count)
/* We're done */
if (data->txstate == WBCIR_TXSTATE_ERROR)
- count = -EAGAIN;
+ ret = -EFAULT;
data->txstate = WBCIR_TXSTATE_INACTIVE;
- data->txbuf = NULL;
spin_unlock_irqrestore(&data->spinlock, flags);
- return count;
+ return ret;
}
/*****************************************************************************
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 4f69aa9..4a5dbcb 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -52,6 +52,24 @@ struct rc_keymap_entry {
};
};
+#define RC_TX_KFIFO_SIZE 1024
+struct ir_raw_event {
+ union {
+ u32 duration;
+
+ struct {
+ u32 carrier;
+ u8 duty_cycle;
+ };
+ };
+
+ unsigned pulse:1;
+ unsigned reset:1;
+ unsigned timeout:1;
+ unsigned carrier_report:1;
+};
+
+
/**
* struct rc_dev - represents a remote control device
* @dev: driver model's view of this device
@@ -67,6 +85,8 @@ struct rc_keymap_entry {
* @exist: used to determine if the device is still valid
* @client_list: list of clients (processes which have opened the rc chardev)
* @client_lock: protects client_list
+ * @txfifo: fifo with tx data to transmit
+ * @txlock: protects txfifo
* @rxwait: waitqueue for processes waiting for data to read
* @raw: additional data for raw pulse/space devices
* @input_dev: the input child device used to communicate events to userspace
@@ -119,6 +139,8 @@ struct rc_dev {
bool exist;
struct list_head client_list;
spinlock_t client_lock;
+ DECLARE_KFIFO_PTR(txfifo, struct ir_raw_event);
+ spinlock_t txlock;
wait_queue_head_t rxwait;
struct ir_raw_event_ctrl *raw;
struct input_dev *input_dev;
@@ -148,7 +170,7 @@ struct rc_dev {
int (*s_tx_carrier)(struct rc_dev *dev, u32 carrier);
int (*s_tx_duty_cycle)(struct rc_dev *dev, u32 duty_cycle);
int (*s_rx_carrier_range)(struct rc_dev *dev, u32 min, u32 max);
- int (*tx_ir)(struct rc_dev *dev, unsigned *txbuf, unsigned n);
+ int (*tx_ir)(struct rc_dev *dev);
void (*s_idle)(struct rc_dev *dev, bool enable);
int (*s_learning_mode)(struct rc_dev *dev, int enable);
int (*s_carrier_report) (struct rc_dev *dev, int enable);
@@ -216,22 +238,6 @@ enum raw_event_type {
IR_STOP_EVENT = (1 << 3),
};
-struct ir_raw_event {
- union {
- u32 duration;
-
- struct {
- u32 carrier;
- u8 duty_cycle;
- };
- };
-
- unsigned pulse:1;
- unsigned reset:1;
- unsigned timeout:1;
- unsigned carrier_report:1;
-};
-
#define DEFINE_IR_RAW_EVENT(event) \
struct ir_raw_event event = { \
{ .duration = 0 } , \
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 14/43] rc-core: allow chardev to be written
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (12 preceding siblings ...)
2012-05-23 9:43 ` [PATCH 13/43] rc-core: use a kfifo for TX data David Härdeman
@ 2012-05-23 9:43 ` David Härdeman
2012-05-23 9:43 ` [PATCH 15/43] rc-core: add ioctl support to the rc chardev David Härdeman
` (29 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Add write functionality to the rc chardev (for use in transmitting remote
control commands on capable hardware).
The data format of the TX data is probably going to have to be dependent
on the rc_driver_type.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-main.c | 68 ++++++++++++++++++++++++++++++++++++++++++++
include/media/rc-core.h | 2 +
2 files changed, 70 insertions(+)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 80d6dac..3389822 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1211,6 +1211,7 @@ struct rc_dev *rc_allocate_device(void)
INIT_KFIFO(dev->txfifo);
spin_lock_init(&dev->txlock);
init_waitqueue_head(&dev->rxwait);
+ init_waitqueue_head(&dev->txwait);
spin_lock_init(&dev->rc_map.lock);
spin_lock_init(&dev->keylock);
mutex_init(&dev->lock);
@@ -1409,6 +1410,7 @@ void rc_unregister_device(struct rc_dev *dev)
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
spin_unlock(&dev->client_lock);
wake_up_interruptible_all(&dev->rxwait);
+ wake_up_interruptible_all(&dev->txwait);
del_timer_sync(&dev->timer_keyup);
@@ -1560,6 +1562,69 @@ static ssize_t rc_read(struct file *file, char __user *buffer,
}
/**
+ * rc_write() - allows userspace to write data to transmit
+ * @file: the &struct file corresponding to the previous open()
+ * @buffer: the userspace buffer to read data from
+ * @count: the number of bytes to read
+ * @ppos: the file offset
+ * @return: the number of bytes written, or a negative error code
+ *
+ * This function (which implements write in &struct file_operations)
+ * allows userspace to transmit data using a suitable rc device
+ */
+static ssize_t rc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct rc_client *client = file->private_data;
+ struct rc_dev *dev = client->dev;
+ ssize_t ret;
+ DEFINE_IR_RAW_EVENT(event);
+ bool pulse = true;
+ u32 value;
+
+ if (!dev->tx_ir)
+ return -ENOSYS;
+
+ if ((count < sizeof(u32)) || (count % sizeof(u32)))
+ return -EINVAL;
+
+again:
+ if (kfifo_is_full(&dev->txfifo) && dev->exist &&
+ (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
+
+ ret = wait_event_interruptible(dev->txwait,
+ !kfifo_is_full(&dev->txfifo) ||
+ !dev->exist);
+ if (ret)
+ return ret;
+
+ if (!dev->exist)
+ return -ENODEV;
+
+ for (ret = 0; ret + sizeof(value) <= count; ret += sizeof(value)) {
+ if (copy_from_user(&value, buffer + ret, sizeof(value)))
+ return -EFAULT;
+
+ event.duration = US_TO_NS(value);
+ event.pulse = pulse;
+ pulse = !pulse;
+
+ if (kfifo_in_spinlocked(&dev->txfifo, &event, 1, &dev->txlock)
+ != 1)
+ break;
+ }
+
+ if (ret == 0)
+ goto again;
+
+ dev->tx_ir(dev);
+ wake_up_interruptible(&dev->txwait);
+
+ return ret;
+}
+
+/**
* rc_poll() - allows userspace to poll rc device files
* @file: the &struct file corresponding to the previous open()
* @wait: used to keep track of processes waiting for poll events
@@ -1573,8 +1638,10 @@ static unsigned int rc_poll(struct file *file, poll_table *wait)
struct rc_client *client = file->private_data;
struct rc_dev *dev = client->dev;
+ poll_wait(file, &dev->txwait, wait);
poll_wait(file, &dev->rxwait, wait);
return ((kfifo_is_empty(&client->rxfifo) ? 0 : (POLLIN | POLLRDNORM)) |
+ (kfifo_is_full(&dev->txfifo) ? 0 : (POLLOUT | POLLWRNORM)) |
(dev->exist ? 0 : (POLLHUP | POLLERR)));
}
@@ -1601,6 +1668,7 @@ static const struct file_operations rc_fops = {
.open = rc_open,
.release = rc_release,
.read = rc_read,
+ .write = rc_write,
.poll = rc_poll,
.fasync = rc_fasync,
};
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 4a5dbcb..1810984 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -87,6 +87,7 @@ struct ir_raw_event {
* @client_lock: protects client_list
* @txfifo: fifo with tx data to transmit
* @txlock: protects txfifo
+ * @txwait: waitqueue for processes waiting to write data to the txfifo
* @rxwait: waitqueue for processes waiting for data to read
* @raw: additional data for raw pulse/space devices
* @input_dev: the input child device used to communicate events to userspace
@@ -141,6 +142,7 @@ struct rc_dev {
spinlock_t client_lock;
DECLARE_KFIFO_PTR(txfifo, struct ir_raw_event);
spinlock_t txlock;
+ wait_queue_head_t txwait;
wait_queue_head_t rxwait;
struct ir_raw_event_ctrl *raw;
struct input_dev *input_dev;
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 15/43] rc-core: add ioctl support to the rc chardev
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (13 preceding siblings ...)
2012-05-23 9:43 ` [PATCH 14/43] rc-core: allow chardev to be written David Härdeman
@ 2012-05-23 9:43 ` David Härdeman
2012-05-23 9:43 ` [PATCH 16/43] rc-core: add an ioctl for getting IR RX settings David Härdeman
` (28 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Add basic support for ioctl operations on the rc chardev.
Only two ioctl's are defined for now: one to get the rc-core
version and one to get the driver type of a given chardev.
Userspace is expected to make sure that both match the expected
values before proceeding with any ioctl/read/write ops.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
Documentation/ioctl/ioctl-number.txt | 1 +
drivers/media/rc/rc-main.c | 66 ++++++++++++++++++++++++++++++++++
include/media/rc-core.h | 19 ++++++++++
3 files changed, 86 insertions(+)
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index e34b531..2a69c0d 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -269,6 +269,7 @@ Code Seq#(hex) Include File Comments
'v' C0-FF linux/meye.h conflict!
'v' D0-DF drivers/media/video/cpia2/cpia2dev.h conflict!
'w' all CERN SCI driver
+'x' all media/rc-core.h Remote Control drivers
'y' 00-1F packet based user level communications
<mailto:zapman@interlan.net>
'z' 00-3F CAN bus card conflict!
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 3389822..d9ed1a8 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1663,6 +1663,68 @@ static int rc_fasync(int fd, struct file *file, int on)
return fasync_helper(fd, file, on, &client->fasync);
}
+/**
+ * rc_do_ioctl() - internal implementation of ioctl handling
+ * @dev: the &struct rc_dev to perform the command on
+ * @cmd: the ioctl command to perform
+ * @arg: the argument to the ioctl cmd
+ * @return: zero on success, or a negative error code
+ *
+ * This function (which is called with the @dev mutex held) performs
+ * the actual processing of ioctl commands.
+ */
+static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
+{
+ void __user *p = (void __user *)arg;
+ unsigned int __user *ip = (unsigned int __user *)p;
+
+ switch (cmd) {
+
+ case RCIOCGVERSION:
+ return put_user(RC_VERSION, ip);
+
+ case RCIOCGTYPE:
+ return put_user(dev->driver_type, ip);
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * rc_ioctl() - allows userspace to do ioctl operations on the rc device file
+ * @fd: the file descriptor corresponding to the opened rc device
+ * @file: the &struct file corresponding to the previous open()
+ * @cmd: the ioctl command to perform
+ * @arg: the argument to the ioctl cmd
+ * @return: zero on success, or a negative error code
+ *
+ * This function (which implements the ioctl functionality in
+ * &struct file_operations) allows userspace to perform various ioctl
+ * operations on a rc device file.
+ */
+static long rc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct rc_client *client = file->private_data;
+ struct rc_dev *dev = client->dev;
+ int ret;
+
+ ret = mutex_lock_interruptible(&dev->lock);
+ if (ret)
+ return ret;
+
+ if (!dev->exist) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ ret = rc_do_ioctl(dev, cmd, arg);
+
+out:
+ mutex_unlock(&dev->lock);
+ return ret;
+}
+
+
static const struct file_operations rc_fops = {
.owner = THIS_MODULE,
.open = rc_open,
@@ -1671,6 +1733,10 @@ static const struct file_operations rc_fops = {
.write = rc_write,
.poll = rc_poll,
.fasync = rc_fasync,
+ .unlocked_ioctl = rc_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = rc_ioctl,
+#endif
};
static int __init rc_core_init(void)
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 1810984..e3d445b 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -29,6 +29,25 @@ do { \
pr_debug("%s: " fmt, __func__, ##__VA_ARGS__); \
} while (0)
+#define RC_VERSION 0x010000
+
+/*
+ * ioctl definitions
+ *
+ * Note: userspace programs which wish to interact with /dev/rc/rc? devices
+ * should make sure that the RC version and driver type is known
+ * (by using RCIOCGVERSION and RCIOCGTYPE) before continuing with any
+ * read/write/ioctl ops.
+ */
+#define RC_IOC_MAGIC 'x'
+
+/* get rc version */
+#define RCIOCGVERSION _IOR(RC_IOC_MAGIC, 0x01, unsigned int)
+
+/* get driver/hardware type */
+#define RCIOCGTYPE _IOR(RC_IOC_MAGIC, 0x02, unsigned int)
+
+
enum rc_driver_type {
RC_DRIVER_SCANCODE = 0, /* Driver or hardware generates a scancode */
RC_DRIVER_IR_RAW, /* Needs a Infra-Red pulse/space decoder */
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 16/43] rc-core: add an ioctl for getting IR RX settings
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (14 preceding siblings ...)
2012-05-23 9:43 ` [PATCH 15/43] rc-core: add ioctl support to the rc chardev David Härdeman
@ 2012-05-23 9:43 ` David Härdeman
2012-05-23 9:43 ` [PATCH 17/43] rc-loopback: add RCIOCGIRRX ioctl support David Härdeman
` (27 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
LIRC currently supports quite a number of ioctl's for getting/setting
various TX and RX parameters. One problem with the one-ioctl-per-parameter
approach is that it might be quite elaborate to reprogram the hardware
(an operation which will have to be done once for every parameter change).
LIRC has approached this problem by providing something similar to
database transactions (ioctl commands LIRC_SETUP_START and LIRC_SETUP_END)
which is one (complicated) way of doing it.
The proposed approach for rc-core instead uses a struct with all known
parameters defined in one go. Drivers are expected to fill in the struct
with all the parameters that apply to them while leaving the rest intact.
I've looked at parameters defined in: LIRC, current rc-core, and in Microsoft
CIRClass drivers. The current struct rc_ir_rx should be a superset of all
three and also has room for further additions. Hopefully this should be fairly
complete and future-proof, please check carefully that you favourite
parameter is supported to satisfy your OCD.
Also, it would be interesting to know if carrier reporting is actually an
expensive operation (which should be explicitly enabled by setting the
appropriate flag as now) or not (in which case it should always be on).
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-main.c | 28 +++++++++++++++++++
include/media/rc-core.h | 65 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 93 insertions(+)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index d9ed1a8..2d3f421 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1677,6 +1677,7 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
{
void __user *p = (void __user *)arg;
unsigned int __user *ip = (unsigned int __user *)p;
+ struct rc_ir_rx rx;
switch (cmd) {
@@ -1685,6 +1686,33 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
case RCIOCGTYPE:
return put_user(dev->driver_type, ip);
+
+ case RCIOCGIRPSIZE:
+ return put_user(ARRAY_SIZE(rx.protocols_supported), ip);
+
+ case RCIOCGIRRX:
+ memset(&rx, 0, sizeof(rx));
+ rx.rx_supported = 0x1;
+ rx.rx_enabled = 0x1;
+ rx.rx_connected = 0x1;
+ rx.protocols_enabled[0] = dev->enabled_protocols;
+ if (dev->driver_type == RC_DRIVER_SCANCODE)
+ rx.protocols_supported[0] = dev->allowed_protos;
+ else
+ rx.protocols_supported[0] = ir_raw_get_allowed_protocols();
+ rx.timeout = dev->timeout;
+ rx.timeout_min = dev->min_timeout;
+ rx.timeout_max = dev->max_timeout;
+ rx.resolution = dev->rx_resolution;
+
+ /* See if the driver wishes to override anything */
+ if (dev->get_ir_rx)
+ dev->get_ir_rx(dev, &rx);
+
+ if (copy_to_user(p, &rx, sizeof(rx)))
+ return -EFAULT;
+
+ return 0;
}
return -EINVAL;
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index e3d445b..5669b64 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -47,6 +47,69 @@ do { \
/* get driver/hardware type */
#define RCIOCGTYPE _IOR(RC_IOC_MAGIC, 0x02, unsigned int)
+/* get size of protocols array (i.e. multiples of u64) for struct rc_ir_rx */
+#define RCIOCGIRPSIZE _IOR(RC_IOC_MAGIC, 0x03, unsigned int)
+
+/* get ir rx parameters */
+#define RCIOCGIRRX _IOC(_IOC_READ, RC_IOC_MAGIC, 0x04, sizeof(struct rc_ir_rx))
+
+/**
+ * struct rc_ir_rx - used to get all IR RX parameters in one go
+ * @flags: device specific flags (only %RC_IR_RX_MEASURE_CARRIER is
+ * currently defined)
+ * @rx_supported: bitmask of supported (i.e. possible) receivers
+ * @rx_enabled: bitmask of enabled receivers
+ * @rx_connected: bitmask of connected receivers
+ * @rx_learning: bitmask of learning receivers
+ * @protocols_supported: bitmask of supported protocols
+ * @protocols_enabled: bitmask of enabled protocols
+ * @freq_min: min carrier frequency
+ * @freq_max: max carrier frequency
+ * @duty_min: min duty cycle
+ * @duty_max: max duty cycle
+ * @timeout: current timeout (i.e. silence-before-idle)
+ * @timeout_min: min timeout
+ * @timeout_max: max timeout
+ * @filter_space: shorter spaces may be filtered
+ * @filter_space_min: min space filter value
+ * @filter_space_max: max space filter value
+ * @filter_pulse: shorter pulses may be filtered
+ * @filter_pulse_min: min pulse filter value
+ * @filter_pulse_max: max pulse filter value
+ * @resolution: current pulse/space resolution
+ * @resolution_min: min resolution
+ * @resolution_max: max resolution
+ * @reserved: for future use, set to zero
+ */
+struct rc_ir_rx {
+ __u32 flags;
+#define RC_IR_RX_MEASURE_CARRIER 0x01
+ __u32 rx_supported;
+ __u32 rx_enabled;
+ __u32 rx_connected;
+ __u32 rx_learning;
+ __u64 protocols_supported[1];
+ __u64 protocols_enabled[1];
+ __u32 freq_min;
+ __u32 freq_max;
+ __u32 duty_min;
+ __u32 duty_max;
+ __u32 timeout;
+ __u32 timeout_min;
+ __u32 timeout_max;
+ __u32 filter_space;
+ __u32 filter_space_min;
+ __u32 filter_space_max;
+ __u32 filter_pulse;
+ __u32 filter_pulse_min;
+ __u32 filter_pulse_max;
+ __u32 resolution;
+ __u32 resolution_min;
+ __u32 resolution_max;
+ __u32 reserved[9];
+} __packed;
+
+
enum rc_driver_type {
RC_DRIVER_SCANCODE = 0, /* Driver or hardware generates a scancode */
@@ -145,6 +208,7 @@ struct ir_raw_event {
* device doesn't interrupt host until it sees IR pulses
* @s_learning_mode: enable wide band receiver used for learning
* @s_carrier_report: enable carrier reports
+ * @get_ir_rx: allow driver to provide rx settings
*/
struct rc_dev {
struct device dev;
@@ -195,6 +259,7 @@ struct rc_dev {
void (*s_idle)(struct rc_dev *dev, bool enable);
int (*s_learning_mode)(struct rc_dev *dev, int enable);
int (*s_carrier_report) (struct rc_dev *dev, int enable);
+ void (*get_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
};
#define to_rc_dev(d) container_of(d, struct rc_dev, dev)
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 17/43] rc-loopback: add RCIOCGIRRX ioctl support
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (15 preceding siblings ...)
2012-05-23 9:43 ` [PATCH 16/43] rc-core: add an ioctl for getting IR RX settings David Härdeman
@ 2012-05-23 9:43 ` David Härdeman
2012-05-23 9:43 ` [PATCH 18/43] rc-core: add an ioctl for setting IR RX settings David Härdeman
` (26 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
As an example, this patch adds support for the new RCIOCGIRRX ioctl
to rc-loopback.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-loopback.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index b6a2e58..7977b75 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -173,6 +173,27 @@ static int loop_set_carrier_report(struct rc_dev *dev, int enable)
return 0;
}
+/**
+ * loop_get_ir_rx() - returns the current RX settings
+ * @dev: the &struct rc_dev to get the settings for
+ * @rx: the &struct rc_ir_rx to fill in with the current settings
+ *
+ * This function is used to return the current RX settings.
+ */
+static void loop_get_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ rx->rx_supported = RXMASK_REGULAR | RXMASK_LEARNING;
+ rx->rx_connected = RXMASK_REGULAR | RXMASK_LEARNING;
+ rx->rx_enabled = lodev->learning ? RXMASK_LEARNING : RXMASK_REGULAR;
+ rx->rx_learning = RXMASK_LEARNING;
+ rx->freq_min = lodev->rxcarriermin;
+ rx->freq_max = lodev->rxcarriermax;
+ rx->duty_min = 1;
+ rx->duty_max = 99;
+}
+
static int __init loop_init(void)
{
struct rc_dev *rc;
@@ -206,6 +227,7 @@ static int __init loop_init(void)
rc->s_idle = loop_set_idle;
rc->s_learning_mode = loop_set_learning_mode;
rc->s_carrier_report = loop_set_carrier_report;
+ rc->get_ir_rx = loop_get_ir_rx;
loopdev.txmask = RXMASK_REGULAR;
loopdev.txcarrier = 36000;
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 18/43] rc-core: add an ioctl for setting IR RX settings
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (16 preceding siblings ...)
2012-05-23 9:43 ` [PATCH 17/43] rc-loopback: add RCIOCGIRRX ioctl support David Härdeman
@ 2012-05-23 9:43 ` David Härdeman
2012-05-23 9:43 ` [PATCH 19/43] rc-loopback: add RCIOCSIRRX ioctl support David Härdeman
` (25 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
This adds a complementary ioctl to allow IR RX settings to be
changed.
Userspace is expected to first call RCIOCGIRRX, change the relevant parameters
in struct rc_ir_rx and then call RCIOCSIRRX.
The struct will be updated to reflect what the driver actually set the
parameters to (as all values may not be possible and some might have
to be approximated, e.g. because the hardware only supports some fixed
values) so that userspace knows the end result.
The LIRC driver is also changed to use the new RCIOCGIRRX and RCIOCSIRRX
methods as an alternative to the old functionality. This allows several
operations in struct rc_dev to be deprecated.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/ir-lirc-codec.c | 53 +++++++++++++++++++++++++++++---------
drivers/media/rc/rc-core-priv.h | 3 ++
drivers/media/rc/rc-main.c | 53 +++++++++++++++++++++++++++++---------
include/media/rc-core.h | 13 ++++++---
4 files changed, 92 insertions(+), 30 deletions(-)
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 795cbdf..767fd06 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -160,6 +160,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
u32 __user *argp = (u32 __user *)(arg);
int ret = 0;
__u32 val = 0, tmp;
+ struct rc_ir_rx rx;
lirc = lirc_get_pdata(filep);
if (!lirc)
@@ -211,15 +212,23 @@ 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;
-
- if (val <= 0)
+ if (val <= 0 || val < dev->raw->lirc.carrier_low)
return -EINVAL;
- return dev->s_rx_carrier_range(dev,
- dev->raw->lirc.carrier_low,
- val);
+ if (dev->s_rx_carrier_range)
+ return dev->s_rx_carrier_range(dev,
+ dev->raw->lirc.carrier_low,
+ val);
+
+ if (dev->get_ir_rx && dev->set_ir_rx) {
+ rc_init_ir_rx(dev, &rx);
+ dev->get_ir_rx(dev, &rx);
+ rx.freq_min = dev->raw->lirc.carrier_low;
+ rx.freq_max = val;
+ return dev->set_ir_rx(dev, &rx);
+ }
+
+ return -ENOSYS;
case LIRC_SET_REC_CARRIER_RANGE:
if (val <= 0)
@@ -233,16 +242,34 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
break;
case LIRC_SET_WIDEBAND_RECEIVER:
- if (!dev->s_learning_mode)
- return -ENOSYS;
+ if (dev->s_learning_mode)
+ return dev->s_learning_mode(dev, !!val);
+
+ if (dev->get_ir_rx && dev->set_ir_rx) {
+ rc_init_ir_rx(dev, &rx);
+ dev->get_ir_rx(dev, &rx);
+ rx.rx_enabled = (!!val) ? rx.rx_learning : ~rx.rx_learning;
+ rx.rx_enabled &= rx.rx_supported;
+ return dev->set_ir_rx(dev, &rx);
+ }
- return dev->s_learning_mode(dev, !!val);
+ return -ENOSYS;
case LIRC_SET_MEASURE_CARRIER_MODE:
- if (!dev->s_carrier_report)
- return -ENOSYS;
+ if (dev->s_carrier_report)
+ return dev->s_carrier_report(dev, !!val);
+
+ if (dev->get_ir_rx && dev->set_ir_rx) {
+ rc_init_ir_rx(dev, &rx);
+ dev->get_ir_rx(dev, &rx);
+ if (!!val)
+ rx.flags |= RC_IR_RX_MEASURE_CARRIER;
+ else
+ rx.flags &= ~RC_IR_RX_MEASURE_CARRIER;
+ return dev->set_ir_rx(dev, &rx);
+ }
- return dev->s_carrier_report(dev, !!val);
+ return -ENOSYS;
/* Generic timeout support */
case LIRC_GET_MIN_TIMEOUT:
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 6a40bc9..8db5bbc 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -149,6 +149,9 @@ 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_init(void);
+/* Only to be used by rc-core and ir-lirc-codec */
+void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx);
+
/*
* Decoder initialization code
*
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 2d3f421..390673c 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1664,6 +1664,31 @@ static int rc_fasync(int fd, struct file *file, int on)
}
/**
+ * rc_init_ir_rx() - initializes a &struct rc_ir_rx to sane defaults
+ * @dev: the &struct rc_dev to take initial settings from
+ * @rx: the &struct rx_ir_rx to fill in with default values
+ *
+ * This function should only to be used by rc-core and ir-lirc-codec.
+ */
+void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx)
+{
+ memset(rx, 0, sizeof(*rx));
+ rx->rx_supported = 0x1;
+ rx->rx_enabled = 0x1;
+ rx->rx_connected = 0x1;
+ rx->protocols_enabled[0] = dev->enabled_protocols;
+ if (dev->driver_type == RC_DRIVER_SCANCODE)
+ rx->protocols_supported[0] = dev->allowed_protos;
+ else
+ rx->protocols_supported[0] = ir_raw_get_allowed_protocols();
+ rx->timeout = dev->timeout;
+ rx->timeout_min = dev->min_timeout;
+ rx->timeout_max = dev->max_timeout;
+ rx->resolution = dev->rx_resolution;
+}
+EXPORT_SYMBOL_GPL(rc_init_ir_rx);
+
+/**
* rc_do_ioctl() - internal implementation of ioctl handling
* @dev: the &struct rc_dev to perform the command on
* @cmd: the ioctl command to perform
@@ -1678,6 +1703,7 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
void __user *p = (void __user *)arg;
unsigned int __user *ip = (unsigned int __user *)p;
struct rc_ir_rx rx;
+ int error;
switch (cmd) {
@@ -1690,20 +1716,21 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
case RCIOCGIRPSIZE:
return put_user(ARRAY_SIZE(rx.protocols_supported), ip);
+ case RCIOCSIRRX:
+ if (!dev->set_ir_rx)
+ return -ENOSYS;
+
+ if (copy_from_user(&rx, p, sizeof(rx)))
+ return -EFAULT;
+
+ error = dev->set_ir_rx(dev, &rx);
+ if (error)
+ return error;
+
+ /* Fall through */
+
case RCIOCGIRRX:
- memset(&rx, 0, sizeof(rx));
- rx.rx_supported = 0x1;
- rx.rx_enabled = 0x1;
- rx.rx_connected = 0x1;
- rx.protocols_enabled[0] = dev->enabled_protocols;
- if (dev->driver_type == RC_DRIVER_SCANCODE)
- rx.protocols_supported[0] = dev->allowed_protos;
- else
- rx.protocols_supported[0] = ir_raw_get_allowed_protocols();
- rx.timeout = dev->timeout;
- rx.timeout_min = dev->min_timeout;
- rx.timeout_max = dev->max_timeout;
- rx.resolution = dev->rx_resolution;
+ rc_init_ir_rx(dev, &rx);
/* See if the driver wishes to override anything */
if (dev->get_ir_rx)
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 5669b64..213b642 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -53,8 +53,11 @@ do { \
/* get ir rx parameters */
#define RCIOCGIRRX _IOC(_IOC_READ, RC_IOC_MAGIC, 0x04, sizeof(struct rc_ir_rx))
+/* set ir rx parameters */
+#define RCIOCSIRRX _IOC(_IOC_WRITE, RC_IOC_MAGIC, 0x04, sizeof(struct rc_ir_rx))
+
/**
- * struct rc_ir_rx - used to get all IR RX parameters in one go
+ * struct rc_ir_rx - used to get/set all IR RX parameters in one go
* @flags: device specific flags (only %RC_IR_RX_MEASURE_CARRIER is
* currently defined)
* @rx_supported: bitmask of supported (i.e. possible) receivers
@@ -202,13 +205,14 @@ struct ir_raw_event {
* @s_tx_mask: set transmitter mask (for devices with multiple tx outputs)
* @s_tx_carrier: set transmit carrier frequency
* @s_tx_duty_cycle: set transmit duty cycle (0% - 100%)
- * @s_rx_carrier: inform driver about carrier it is expected to handle
+ * @s_rx_carrier: inform driver about expected carrier (deprecated)
* @tx_ir: transmit IR
* @s_idle: enable/disable hardware idle mode, upon which,
* device doesn't interrupt host until it sees IR pulses
- * @s_learning_mode: enable wide band receiver used for learning
- * @s_carrier_report: enable carrier reports
+ * @s_learning_mode: enable wide band receiver used for learning (deprecated)
+ * @s_carrier_report: enable carrier reports (deprecated)
* @get_ir_rx: allow driver to provide rx settings
+ * @set_ir_rx: allow driver to change rx settings
*/
struct rc_dev {
struct device dev;
@@ -260,6 +264,7 @@ struct rc_dev {
int (*s_learning_mode)(struct rc_dev *dev, int enable);
int (*s_carrier_report) (struct rc_dev *dev, int enable);
void (*get_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
+ int (*set_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
};
#define to_rc_dev(d) container_of(d, struct rc_dev, dev)
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 19/43] rc-loopback: add RCIOCSIRRX ioctl support
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (17 preceding siblings ...)
2012-05-23 9:43 ` [PATCH 18/43] rc-core: add an ioctl for setting IR RX settings David Härdeman
@ 2012-05-23 9:43 ` David Härdeman
2012-05-23 9:43 ` [PATCH 20/43] rc-core: add an ioctl for getting IR TX settings David Härdeman
` (24 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
As an example, this patch adds support for the new RCIOCSIRRX ioctl
to rc-loopback and removes deprecated functions without a loss in
functionality (as LIRC will automatically use the new functions).
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-loopback.c | 84 ++++++++++++++++++++--------------------
1 file changed, 42 insertions(+), 42 deletions(-)
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 7977b75..6d0e9fb 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -86,21 +86,6 @@ static int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
return 0;
}
-static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max)
-{
- struct loopback_dev *lodev = dev->priv;
-
- if (min < 1 || min > max) {
- dprintk("invalid rx carrier range %u to %u\n", min, max);
- return -EINVAL;
- }
-
- dprintk("setting rx carrier range %u to %u\n", min, max);
- lodev->rxcarriermin = min;
- lodev->rxcarriermax = max;
- return 0;
-}
-
static int loop_tx_ir(struct rc_dev *dev)
{
struct loopback_dev *lodev = dev->priv;
@@ -149,30 +134,6 @@ static void loop_set_idle(struct rc_dev *dev, bool enable)
}
}
-static int loop_set_learning_mode(struct rc_dev *dev, int enable)
-{
- struct loopback_dev *lodev = dev->priv;
-
- if (lodev->learning != enable) {
- dprintk("%sing learning mode\n", enable ? "enter" : "exit");
- lodev->learning = !!enable;
- }
-
- return 0;
-}
-
-static int loop_set_carrier_report(struct rc_dev *dev, int enable)
-{
- struct loopback_dev *lodev = dev->priv;
-
- if (lodev->carrierreport != enable) {
- dprintk("%sabling carrier reports\n", enable ? "en" : "dis");
- lodev->carrierreport = !!enable;
- }
-
- return 0;
-}
-
/**
* loop_get_ir_rx() - returns the current RX settings
* @dev: the &struct rc_dev to get the settings for
@@ -194,6 +155,47 @@ static void loop_get_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx)
rx->duty_max = 99;
}
+/**
+ * loop_set_ir_rx() - changes and returns the current RX settings
+ * @dev: the &struct rc_dev to change the settings for
+ * @rx: the &struct rc_ir_rx with the new settings
+ *
+ * This function is used to change and return the current RX settings.
+ */
+static int loop_set_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ dprintk("%s called\n", __func__);
+ if (lodev->rxcarriermin != rx->freq_min) {
+ dprintk("changing rx carrier min to %u\n", rx->freq_min);
+ lodev->rxcarriermin = rx->freq_min;
+ }
+
+ if (lodev->rxcarriermax != rx->freq_max) {
+ dprintk("changing rx carrier max to %u\n", rx->freq_max);
+ lodev->rxcarriermax = rx->freq_max;
+ }
+
+ if (lodev->carrierreport == !(rx->flags & RC_IR_RX_MEASURE_CARRIER)) {
+ lodev->carrierreport = !!(rx->flags & RC_IR_RX_MEASURE_CARRIER);
+ dprintk("%sabling carrier reports\n",
+ lodev->carrierreport ? "en" : "dis");
+ }
+
+ if ((rx->rx_enabled == RXMASK_LEARNING) && !lodev->learning) {
+ dprintk("enabling learning mode\n");
+ lodev->learning = true;
+ } else if ((rx->rx_enabled == RXMASK_REGULAR) && lodev->learning) {
+ dprintk("disabling learning mode\n");
+ lodev->learning = false;
+ }
+
+ /* Fill in the correct values after the changes */
+ loop_get_ir_rx(dev, rx);
+ return 0;
+}
+
static int __init loop_init(void)
{
struct rc_dev *rc;
@@ -222,12 +224,10 @@ static int __init loop_init(void)
rc->s_tx_mask = loop_set_tx_mask;
rc->s_tx_carrier = loop_set_tx_carrier;
rc->s_tx_duty_cycle = loop_set_tx_duty_cycle;
- rc->s_rx_carrier_range = loop_set_rx_carrier_range;
rc->tx_ir = loop_tx_ir;
rc->s_idle = loop_set_idle;
- rc->s_learning_mode = loop_set_learning_mode;
- rc->s_carrier_report = loop_set_carrier_report;
rc->get_ir_rx = loop_get_ir_rx;
+ rc->set_ir_rx = loop_set_ir_rx;
loopdev.txmask = RXMASK_REGULAR;
loopdev.txcarrier = 36000;
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 20/43] rc-core: add an ioctl for getting IR TX settings
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (18 preceding siblings ...)
2012-05-23 9:43 ` [PATCH 19/43] rc-loopback: add RCIOCSIRRX ioctl support David Härdeman
@ 2012-05-23 9:43 ` David Härdeman
2012-05-23 9:43 ` [PATCH 21/43] rc-loopback: add RCIOCGIRTX ioctl support David Härdeman
` (23 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
This ioctl follows the same rationale and structure as the ioctl for
getting IR RX settings (RCIOCGIRRX) but it works on TX settings instead.
As with the RX ioctl, it would be nice if people could check struct
rc_ir_tx carefully to make sure that their favourite parameter
hasn't been left out.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-main.c | 12 ++++++++++++
include/media/rc-core.h | 38 ++++++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 390673c..e2b2e8c 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1703,6 +1703,7 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
void __user *p = (void __user *)arg;
unsigned int __user *ip = (unsigned int __user *)p;
struct rc_ir_rx rx;
+ struct rc_ir_tx tx;
int error;
switch (cmd) {
@@ -1740,6 +1741,17 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
return -EFAULT;
return 0;
+
+ case RCIOCGIRTX:
+ memset(&tx, 0, sizeof(tx));
+
+ if (dev->get_ir_tx)
+ dev->get_ir_tx(dev, &tx);
+
+ if (copy_to_user(p, &tx, sizeof(tx)))
+ return -EFAULT;
+
+ return 0;
}
return -EINVAL;
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 213b642..9f3645b 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -112,6 +112,42 @@ struct rc_ir_rx {
__u32 reserved[9];
} __packed;
+/* get ir tx parameters */
+#define RCIOCGIRTX _IOC(_IOC_READ, RC_IOC_MAGIC, 0x05, sizeof(struct rc_ir_tx))
+
+/**
+ * struct rc_ir_tx - used to get all IR TX parameters in one go
+ * @flags: device specific flags
+ * @tx_supported: bitmask of supported transmitters
+ * @tx_enabled: bitmask of enabled transmitters
+ * @tx_connected: bitmask of connected transmitters
+ * @freq: current carrier frequency
+ * @freq_min: min carrier frequency
+ * @freq_max: max carrier frequency
+ * @duty: current duty cycle
+ * @duty_min: min duty cycle
+ * @duty_max: max duty cycle
+ * @resolution: current resolution
+ * @resolution_min: min resolution
+ * @resolution_max: max resolution
+ * @reserved: for future use, set to zero
+ */
+struct rc_ir_tx {
+ __u32 flags;
+ __u32 tx_supported;
+ __u32 tx_enabled;
+ __u32 tx_connected;
+ __u32 freq;
+ __u32 freq_min;
+ __u32 freq_max;
+ __u32 duty;
+ __u32 duty_min;
+ __u32 duty_max;
+ __u32 resolution;
+ __u32 resolution_min;
+ __u32 resolution_max;
+ __u32 reserved[9];
+} __packed;
enum rc_driver_type {
@@ -213,6 +249,7 @@ struct ir_raw_event {
* @s_carrier_report: enable carrier reports (deprecated)
* @get_ir_rx: allow driver to provide rx settings
* @set_ir_rx: allow driver to change rx settings
+ * @get_ir_tx: allow driver to provide tx settings
*/
struct rc_dev {
struct device dev;
@@ -265,6 +302,7 @@ struct rc_dev {
int (*s_carrier_report) (struct rc_dev *dev, int enable);
void (*get_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
int (*set_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
+ void (*get_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
};
#define to_rc_dev(d) container_of(d, struct rc_dev, dev)
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 21/43] rc-loopback: add RCIOCGIRTX ioctl support
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (19 preceding siblings ...)
2012-05-23 9:43 ` [PATCH 20/43] rc-core: add an ioctl for getting IR TX settings David Härdeman
@ 2012-05-23 9:43 ` David Härdeman
2012-05-23 9:43 ` [PATCH 22/43] rc-core: add an ioctl for setting IR TX settings David Härdeman
` (22 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
As an example, this patch adds support for the new RCIOCGIRRX ioctl
to rc-loopback.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-loopback.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 6d0e9fb..a04b39b 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -196,6 +196,31 @@ static int loop_set_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx)
return 0;
}
+/**
+ * loop_get_ir_tx() - returns the current TX settings
+ * @dev: the &struct rc_dev to get the settings for
+ * @tx: the &struct rc_ir_tx to fill in with the current settings
+ *
+ * This function is used to return the current TX settings.
+ */
+static void loop_get_ir_tx(struct rc_dev *dev, struct rc_ir_tx *tx)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ tx->tx_supported = RXMASK_REGULAR | RXMASK_LEARNING;
+ tx->tx_connected = RXMASK_REGULAR | RXMASK_LEARNING;
+ tx->tx_enabled = lodev->txmask;
+ tx->freq = lodev->txcarrier;
+ tx->freq_min = 1;
+ tx->freq_max = UINT_MAX;
+ tx->duty = lodev->txduty;
+ tx->duty_min = 1;
+ tx->duty_max = 99;
+ tx->resolution = 1;
+ tx->resolution_min = 1;
+ tx->resolution_max = 1;
+}
+
static int __init loop_init(void)
{
struct rc_dev *rc;
@@ -228,6 +253,7 @@ static int __init loop_init(void)
rc->s_idle = loop_set_idle;
rc->get_ir_rx = loop_get_ir_rx;
rc->set_ir_rx = loop_set_ir_rx;
+ rc->get_ir_tx = loop_get_ir_tx;
loopdev.txmask = RXMASK_REGULAR;
loopdev.txcarrier = 36000;
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 22/43] rc-core: add an ioctl for setting IR TX settings
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (20 preceding siblings ...)
2012-05-23 9:43 ` [PATCH 21/43] rc-loopback: add RCIOCGIRTX ioctl support David Härdeman
@ 2012-05-23 9:43 ` David Härdeman
2012-05-23 9:44 ` [PATCH 23/43] rc-loopback: add RCIOCSIRTX ioctl support David Härdeman
` (21 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:43 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
This adds a complementary ioctl to allow IR TX settings to be
changed.
Much like the RCIOCSIRRX functionality, userspace is expected to call
RCIOCGIRTX, change values and then call RCIOCSIRTX and finally inspect
the struct rc_ir_tx to see the results.
Also, LIRC is changed to use the new functionality as an alternative to the
old one and another bunch of operations in struct rc_dev are now deprecated.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/ir-lirc-codec.c | 42 +++++++++++++++++++++++++++++---------
drivers/media/rc/rc-main.c | 13 ++++++++++++
include/media/rc-core.h | 13 ++++++++----
3 files changed, 54 insertions(+), 14 deletions(-)
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 767fd06..6811db9 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -161,6 +161,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
int ret = 0;
__u32 val = 0, tmp;
struct rc_ir_rx rx;
+ struct rc_ir_tx tx;
lirc = lirc_get_pdata(filep);
if (!lirc)
@@ -190,25 +191,46 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
/* TX settings */
case LIRC_SET_TRANSMITTER_MASK:
- if (!dev->s_tx_mask)
- return -EINVAL;
+ if (dev->s_tx_mask)
+ return dev->s_tx_mask(dev, val);
- return dev->s_tx_mask(dev, val);
+ if (dev->get_ir_tx && dev->set_ir_tx) {
+ memset(&tx, 0, sizeof(tx));
+ dev->get_ir_tx(dev, &tx);
+ tx.tx_enabled = val;
+ return dev->set_ir_tx(dev, &tx);
+ }
+
+ return -EINVAL;
case LIRC_SET_SEND_CARRIER:
- if (!dev->s_tx_carrier)
- return -EINVAL;
+ if (dev->s_tx_carrier)
+ return dev->s_tx_carrier(dev, val);
- return dev->s_tx_carrier(dev, val);
+ if (dev->get_ir_tx && dev->set_ir_tx) {
+ memset(&tx, 0, sizeof(tx));
+ dev->get_ir_tx(dev, &tx);
+ tx.freq = val;
+ return dev->set_ir_tx(dev, &tx);
+ }
- case LIRC_SET_SEND_DUTY_CYCLE:
- if (!dev->s_tx_duty_cycle)
- return -ENOSYS;
+ return -EINVAL;
+ case LIRC_SET_SEND_DUTY_CYCLE:
if (val <= 0 || val >= 100)
return -EINVAL;
- return dev->s_tx_duty_cycle(dev, val);
+ if (dev->s_tx_duty_cycle)
+ return dev->s_tx_duty_cycle(dev, val);
+
+ if (dev->get_ir_tx && dev->set_ir_tx) {
+ memset(&tx, 0, sizeof(tx));
+ dev->get_ir_tx(dev, &tx);
+ tx.duty = val;
+ return dev->set_ir_tx(dev, &tx);
+ }
+
+ return -ENOSYS;
/* RX settings */
case LIRC_SET_REC_CARRIER:
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index e2b2e8c..f8a63e2 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1742,6 +1742,19 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
return 0;
+ case RCIOCSIRTX:
+ if (!dev->set_ir_tx)
+ return -ENOSYS;
+
+ if (copy_from_user(&tx, p, sizeof(tx)))
+ return -EFAULT;
+
+ error = dev->set_ir_tx(dev, &tx);
+ if (error)
+ return error;
+
+ /* Fall through */
+
case RCIOCGIRTX:
memset(&tx, 0, sizeof(tx));
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 9f3645b..843f363 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -115,8 +115,11 @@ struct rc_ir_rx {
/* get ir tx parameters */
#define RCIOCGIRTX _IOC(_IOC_READ, RC_IOC_MAGIC, 0x05, sizeof(struct rc_ir_tx))
+/* set ir tx parameters */
+#define RCIOCSIRTX _IOC(_IOC_WRITE, RC_IOC_MAGIC, 0x05, sizeof(struct rc_ir_tx))
+
/**
- * struct rc_ir_tx - used to get all IR TX parameters in one go
+ * struct rc_ir_tx - used to get/set all IR TX parameters in one go
* @flags: device specific flags
* @tx_supported: bitmask of supported transmitters
* @tx_enabled: bitmask of enabled transmitters
@@ -238,9 +241,9 @@ struct ir_raw_event {
* is opened.
* @close: callback to allow drivers to disable polling/irq when IR input device
* is opened.
- * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs)
- * @s_tx_carrier: set transmit carrier frequency
- * @s_tx_duty_cycle: set transmit duty cycle (0% - 100%)
+ * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs, deprecated)
+ * @s_tx_carrier: set transmit carrier frequency (deprecated)
+ * @s_tx_duty_cycle: set transmit duty cycle (0% - 100%, deprecated)
* @s_rx_carrier: inform driver about expected carrier (deprecated)
* @tx_ir: transmit IR
* @s_idle: enable/disable hardware idle mode, upon which,
@@ -250,6 +253,7 @@ struct ir_raw_event {
* @get_ir_rx: allow driver to provide rx settings
* @set_ir_rx: allow driver to change rx settings
* @get_ir_tx: allow driver to provide tx settings
+ * @set_ir_tx: allow driver to change tx settings
*/
struct rc_dev {
struct device dev;
@@ -303,6 +307,7 @@ struct rc_dev {
void (*get_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
int (*set_ir_rx)(struct rc_dev *dev, struct rc_ir_rx *rx);
void (*get_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
+ int (*set_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
};
#define to_rc_dev(d) container_of(d, struct rc_dev, dev)
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 23/43] rc-loopback: add RCIOCSIRTX ioctl support
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (21 preceding siblings ...)
2012-05-23 9:43 ` [PATCH 22/43] rc-core: add an ioctl for setting IR TX settings David Härdeman
@ 2012-05-23 9:44 ` David Härdeman
2012-05-23 9:44 ` [PATCH 24/43] rc-core: leave the internals of rc_dev alone David Härdeman
` (20 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:44 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
As an example, this patch adds support for the new RCIOCSIRTX ioctl
to rc-loopback and removes deprecated functions without a loss in
functionality (as LIRC will automatically use the new functions).
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-loopback.c | 59 +++++++++++++---------------------------
1 file changed, 19 insertions(+), 40 deletions(-)
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index a04b39b..de9a75e 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -49,43 +49,6 @@ struct loopback_dev {
static struct loopback_dev loopdev;
-static int loop_set_tx_mask(struct rc_dev *dev, u32 mask)
-{
- struct loopback_dev *lodev = dev->priv;
-
- if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) {
- dprintk("invalid tx mask: %u\n", mask);
- return -EINVAL;
- }
-
- dprintk("setting tx mask: %u\n", mask);
- lodev->txmask = mask;
- return 0;
-}
-
-static int loop_set_tx_carrier(struct rc_dev *dev, u32 carrier)
-{
- struct loopback_dev *lodev = dev->priv;
-
- dprintk("setting tx carrier: %u\n", carrier);
- lodev->txcarrier = carrier;
- return 0;
-}
-
-static int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
-{
- struct loopback_dev *lodev = dev->priv;
-
- if (duty_cycle < 1 || duty_cycle > 99) {
- dprintk("invalid duty cycle: %u\n", duty_cycle);
- return -EINVAL;
- }
-
- dprintk("setting duty cycle: %u\n", duty_cycle);
- lodev->txduty = duty_cycle;
- return 0;
-}
-
static int loop_tx_ir(struct rc_dev *dev)
{
struct loopback_dev *lodev = dev->priv;
@@ -221,6 +184,24 @@ static void loop_get_ir_tx(struct rc_dev *dev, struct rc_ir_tx *tx)
tx->resolution_max = 1;
}
+/**
+ * loop_set_ir_tx() - changes and returns the current TX settings
+ * @dev: the &struct rc_dev to change the settings for
+ * @tx: the &struct rc_ir_tx with the new settings
+ *
+ * This function is used to change and return the current TX settings.
+ */
+static int loop_set_ir_tx(struct rc_dev *dev, struct rc_ir_tx *tx)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ lodev->txmask = tx->tx_enabled & (RXMASK_REGULAR | RXMASK_LEARNING);
+ lodev->txcarrier = tx->freq;
+ lodev->txduty = tx->duty;
+
+ return 0;
+}
+
static int __init loop_init(void)
{
struct rc_dev *rc;
@@ -246,14 +227,12 @@ static int __init loop_init(void)
rc->max_timeout = UINT_MAX;
rc->rx_resolution = 1000;
rc->tx_resolution = 1000;
- rc->s_tx_mask = loop_set_tx_mask;
- rc->s_tx_carrier = loop_set_tx_carrier;
- rc->s_tx_duty_cycle = loop_set_tx_duty_cycle;
rc->tx_ir = loop_tx_ir;
rc->s_idle = loop_set_idle;
rc->get_ir_rx = loop_get_ir_rx;
rc->set_ir_rx = loop_set_ir_rx;
rc->get_ir_tx = loop_get_ir_tx;
+ rc->set_ir_tx = loop_set_ir_tx;
loopdev.txmask = RXMASK_REGULAR;
loopdev.txcarrier = 36000;
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 24/43] rc-core: leave the internals of rc_dev alone
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (22 preceding siblings ...)
2012-05-23 9:44 ` [PATCH 23/43] rc-loopback: add RCIOCSIRTX ioctl support David Härdeman
@ 2012-05-23 9:44 ` David Härdeman
2012-05-23 9:44 ` [PATCH 25/43] rc-core: prepare for multiple keytables David Härdeman
` (19 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:44 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Several drivers poke around in the internals of rc_dev, try to
fix them up in preparation for the next round of patches.
drivers/media/rc/ati_remote.c:
Removing the REP_DELAY setting on the input device should not
change how to driver works (as it does a keydown/keyup and has
no real repeat handling).
drivers/media/rc/ir-nec-decoder.c
Obvious fix, leave repeat handling to rc-core
drivers/media/rc/ir-raw.c
Replaced the REP_DELAY value with a static value, which makes more
sense anyway. Why should the time before automatic repeat handling
kicks in define the drivers idea of "a long time"?
drivers/media/rc/ir-sanyo-decoder.c
Obvious fix, leave repeat handling to rc-core
drivers/media/video/cx231xx/cx231xx-input.c
Just some debug statements to change
drivers/media/video/tm6000/tm6000-input.c
Not sure what the driver is trying to do, however, IR
handling seems incomplete ATM so deleting the offending
parts shouldn't affect funcationality
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/ati_remote.c | 3 ---
drivers/media/rc/ir-nec-decoder.c | 10 +++-------
drivers/media/rc/ir-raw.c | 4 +---
drivers/media/rc/ir-sanyo-decoder.c | 10 +++-------
drivers/media/video/cx231xx/cx231xx-input.c | 7 +++----
drivers/media/video/tm6000/tm6000-input.c | 4 ----
6 files changed, 10 insertions(+), 28 deletions(-)
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 229f742..f10af75 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -918,9 +918,6 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
if (err)
goto fail3;
- /* use our delay for rc_dev */
- ati_remote->rdev->input_dev->rep[REP_DELAY] = repeat_delay;
-
/* Set up and register mouse input device */
if (mouse) {
input_dev = input_allocate_device();
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 1033f30..c92b229 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -89,13 +89,9 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
data->state = STATE_BIT_PULSE;
return 0;
} else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
- if (!dev->keypressed) {
- IR_dprintk(1, "Discarding last key repeat: event after key up\n");
- } else {
- rc_repeat(dev);
- IR_dprintk(1, "Repeat last key\n");
- data->state = STATE_TRAILER_PULSE;
- }
+ rc_repeat(dev);
+ IR_dprintk(1, "Repeat last key\n");
+ data->state = STATE_TRAILER_PULSE;
return 0;
}
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 7729abe..6ef1510 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -114,20 +114,18 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
s64 delta; /* ns */
DEFINE_IR_RAW_EVENT(ev);
int rc = 0;
- int delay;
if (!dev->raw)
return -EINVAL;
now = ktime_get();
delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
- delay = MS_TO_NS(dev->input_dev->rep[REP_DELAY]);
/* Check for a long duration since last event or if we're
* being called for the first time, note that delta can't
* possibly be negative.
*/
- if (delta > delay || !dev->raw->last_type)
+ if (delta > MS_TO_NS(500) || !dev->raw->last_type)
type |= IR_START_EVENT;
else
ev.duration = delta;
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index a95c869..17ee339 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -112,13 +112,9 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
break;
if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
- if (!dev->keypressed) {
- IR_dprintk(1, "SANYO discarding last key repeat: event after key up\n");
- } else {
- rc_repeat(dev);
- IR_dprintk(1, "SANYO repeat last key\n");
- data->state = STATE_INACTIVE;
- }
+ rc_repeat(dev);
+ IR_dprintk(1, "SANYO repeat last key\n");
+ data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c
index 0f7b424..25385d9 100644
--- a/drivers/media/video/cx231xx/cx231xx-input.c
+++ b/drivers/media/video/cx231xx/cx231xx-input.c
@@ -30,9 +30,9 @@ static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key,
int rc;
u8 cmd, scancode;
- dev_dbg(&ir->rc->input_dev->dev, "%s\n", __func__);
+ dev_dbg(&ir->rc->dev, "cmd %02x, scan = %02x\n", cmd, scancode);
- /* poll IR chip */
+ /* poll IR chip */
rc = i2c_master_recv(ir->c, &cmd, 1);
if (rc < 0)
return rc;
@@ -56,8 +56,7 @@ static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key,
((cmd & 0x40) ? 0x02 : 0) |
((cmd & 0x80) ? 0x01 : 0);
- dev_dbg(&ir->rc->input_dev->dev, "cmd %02x, scan = %02x\n",
- cmd, scancode);
+ dev_dbg(&ir->rc->dev, "cmd %02x, scan = %02x\n", cmd, scancode);
*ir_key = scancode;
*ir_raw = scancode;
diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c
index 6fc0a71..4f6995f 100644
--- a/drivers/media/video/tm6000/tm6000-input.c
+++ b/drivers/media/video/tm6000/tm6000-input.c
@@ -63,7 +63,6 @@ struct tm6000_IR {
u8 wait:1;
u8 pwled:2;
u8 submit_urb:1;
- u16 key_addr;
struct urb *int_urb;
/* IR device properties */
@@ -321,9 +320,6 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
dprintk(2, "%s\n",__func__);
- if ((rc->rc_map.scan) && (rc_type == RC_BIT_NEC))
- ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff);
-
ir->rc_type = rc_type;
tm6000_ir_config(ir);
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 25/43] rc-core: prepare for multiple keytables
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (23 preceding siblings ...)
2012-05-23 9:44 ` [PATCH 24/43] rc-core: leave the internals of rc_dev alone David Härdeman
@ 2012-05-23 9:44 ` David Härdeman
2012-05-23 9:44 ` [PATCH 26/43] rc-core: do not take mutex on rc_dev registration David Härdeman
` (18 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:44 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Introduce struct rc_keytable which essentially maintains an input device
and a table with scancode,protocol <-> keycode mappings. Move the relevant
members from struct rc_dev into struct rc_keytable.
Also, all code related to struct rc_keytable is moved into a separate
file as the rc-main.c one is getting quite large and the rc_keytable
is logically separate code (as will be apparent with the later patches).
This is in preparation for supporting multiple keytables, where each
keytable would correspond to one physical remote controller, each with
its own keymap and input device for reporting events to userspace.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/Makefile | 2
drivers/media/rc/rc-core-priv.h | 10
drivers/media/rc/rc-keytable.c | 890 +++++++++++++++++++++++++++++++++++++++
drivers/media/rc/rc-main.c | 887 ++-------------------------------------
include/media/rc-core.h | 45 +-
5 files changed, 982 insertions(+), 852 deletions(-)
create mode 100644 drivers/media/rc/rc-keytable.c
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 596060a..f470a3f 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -1,4 +1,4 @@
-rc-core-objs := rc-main.o ir-raw.o
+rc-core-objs := rc-main.o rc-keytable.o ir-raw.o
obj-y += keymaps/
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 8db5bbc..7aaa1bf 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -149,6 +149,16 @@ 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_init(void);
+/*
+ * Methods from rc-keytable.c to be used internally
+ */
+void rc_keytable_keyup(struct rc_keytable *kt);
+void rc_keytable_repeat(struct rc_keytable *kt);
+void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
+ u64 scancode, u8 toggle, bool autokeyup);
+struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *map_name);
+void rc_keytable_destroy(struct rc_keytable *kt);
+
/* Only to be used by rc-core and ir-lirc-codec */
void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx);
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
new file mode 100644
index 0000000..7096f44
--- /dev/null
+++ b/drivers/media/rc/rc-keytable.c
@@ -0,0 +1,890 @@
+/*
+ * rc-keytable.c - Remote Controller keytable handling
+ *
+ * Copyright (C) 2009-2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <media/rc-core.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include "rc-core-priv.h"
+
+/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
+#define RC_TAB_MIN_SIZE 256
+#define RC_TAB_MAX_SIZE 8192
+
+/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
+#define IR_KEYPRESS_TIMEOUT 250
+
+/* Used to keep track of known keymaps */
+static LIST_HEAD(rc_map_list);
+static DEFINE_SPINLOCK(rc_map_lock);
+
+static struct rc_map_list *seek_rc_map(const char *name)
+{
+ struct rc_map_list *map = NULL;
+
+ spin_lock(&rc_map_lock);
+ list_for_each_entry(map, &rc_map_list, list) {
+ if (!strcmp(name, map->map.name)) {
+ spin_unlock(&rc_map_lock);
+ return map;
+ }
+ }
+ spin_unlock(&rc_map_lock);
+
+ return NULL;
+}
+
+struct rc_map *rc_map_get(const char *name)
+{
+
+ struct rc_map_list *map;
+
+ map = seek_rc_map(name);
+#ifdef MODULE
+ if (!map) {
+ int rc = request_module(name);
+ if (rc < 0) {
+ printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
+ return NULL;
+ }
+ msleep(20); /* Give some time for IR to register */
+
+ map = seek_rc_map(name);
+ }
+#endif
+ if (!map) {
+ printk(KERN_ERR "IR keymap %s not found\n", name);
+ return NULL;
+ }
+
+ printk(KERN_INFO "Registered IR keymap %s\n", map->map.name);
+
+ return &map->map;
+}
+EXPORT_SYMBOL_GPL(rc_map_get);
+
+int rc_map_register(struct rc_map_list *map)
+{
+ spin_lock(&rc_map_lock);
+ list_add_tail(&map->list, &rc_map_list);
+ spin_unlock(&rc_map_lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rc_map_register);
+
+void rc_map_unregister(struct rc_map_list *map)
+{
+ spin_lock(&rc_map_lock);
+ list_del(&map->list);
+ spin_unlock(&rc_map_lock);
+}
+EXPORT_SYMBOL_GPL(rc_map_unregister);
+
+/**
+ * ir_create_table() - initializes a scancode table
+ * @rc_map: the rc_map to initialize
+ * @name: name to assign to the table
+ * @size: initial size of the table
+ * @return: zero on success or a negative error code
+ *
+ * This routine will initialize the rc_map and will allocate
+ * memory to hold at least the specified number of elements.
+ */
+static int ir_create_table(struct rc_map *rc_map,
+ const char *name, size_t size)
+{
+ rc_map->name = name;
+ rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
+ rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
+ rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
+ if (!rc_map->scan)
+ return -ENOMEM;
+
+ IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+ rc_map->size, rc_map->alloc);
+ return 0;
+}
+
+/**
+ * ir_free_table() - frees memory allocated by a scancode table
+ * @rc_map: the table whose mappings need to be freed
+ *
+ * This routine will free memory alloctaed for key mappings used by given
+ * scancode table.
+ */
+static void ir_free_table(struct rc_map *rc_map)
+{
+ rc_map->size = 0;
+ kfree(rc_map->scan);
+ rc_map->scan = NULL;
+}
+
+/**
+ * ir_resize_table() - resizes a scancode table if necessary
+ * @rc_map: the rc_map to resize
+ * @gfp_flags: gfp flags to use when allocating memory
+ * @return: zero on success or a negative error code
+ *
+ * This routine will shrink the rc_map if it has lots of
+ * unused entries and grow it if it is full.
+ */
+static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
+{
+ unsigned int oldalloc = rc_map->alloc;
+ unsigned int newalloc = oldalloc;
+ struct rc_map_table *oldscan = rc_map->scan;
+ struct rc_map_table *newscan;
+
+ if (rc_map->size == rc_map->len) {
+ /* All entries in use -> grow keytable */
+ if (rc_map->alloc >= RC_TAB_MAX_SIZE)
+ return -ENOMEM;
+
+ newalloc *= 2;
+ IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
+ }
+
+ if ((rc_map->len * 3 < rc_map->size) && (oldalloc > RC_TAB_MIN_SIZE)) {
+ /* Less than 1/3 of entries in use -> shrink keytable */
+ newalloc /= 2;
+ IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
+ }
+
+ if (newalloc == oldalloc)
+ return 0;
+
+ newscan = kmalloc(newalloc, gfp_flags);
+ if (!newscan) {
+ IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
+ return -ENOMEM;
+ }
+
+ memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table));
+ rc_map->scan = newscan;
+ rc_map->alloc = newalloc;
+ rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
+ kfree(oldscan);
+ return 0;
+}
+
+/**
+ * ir_update_mapping() - set a keycode in the scancode->keycode table
+ * @kt: the struct rc_keytable descriptor
+ * @rc_map: scancode table to be adjusted
+ * @index: index of the mapping that needs to be updated
+ * @keycode: the desired keycode
+ * @return: previous keycode assigned to the mapping
+ *
+ * This routine is used to update scancode->keycode mapping at given
+ * position.
+ */
+static unsigned int ir_update_mapping(struct rc_keytable *kt,
+ struct rc_map *rc_map,
+ unsigned int index,
+ unsigned int new_keycode)
+{
+ int old_keycode = rc_map->scan[index].keycode;
+ int i;
+
+ /* Did the user wish to remove the mapping? */
+ if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
+ IR_dprintk(1, "#%d: Deleting proto 0x%04x, scan 0x%08llx\n",
+ index, rc_map->scan[index].protocol,
+ (unsigned long long)rc_map->scan[index].scancode);
+ rc_map->len--;
+ memmove(&rc_map->scan[index], &rc_map->scan[index + 1],
+ (rc_map->len - index) * sizeof(struct rc_map_table));
+ } else {
+ IR_dprintk(1, "#%d: %s proto 0x%04x, scan 0x%08llx "
+ "with key 0x%04x\n",
+ index,
+ old_keycode == KEY_RESERVED ? "New" : "Replacing",
+ rc_map->scan[index].protocol,
+ (unsigned long long)rc_map->scan[index].scancode,
+ new_keycode);
+ rc_map->scan[index].keycode = new_keycode;
+ __set_bit(new_keycode, kt->idev->keybit);
+ }
+
+ if (old_keycode != KEY_RESERVED) {
+ /* A previous mapping was updated... */
+ __clear_bit(old_keycode, kt->idev->keybit);
+ /* ... but another scancode might use the same keycode */
+ for (i = 0; i < rc_map->len; i++) {
+ if (rc_map->scan[i].keycode == old_keycode) {
+ __set_bit(old_keycode, kt->idev->keybit);
+ break;
+ }
+ }
+
+ /* Possibly shrink the keytable, failure is not a problem */
+ ir_resize_table(rc_map, GFP_ATOMIC);
+ }
+
+ return old_keycode;
+}
+
+/**
+ * ir_establish_scancode() - set a keycode in the scancode->keycode table
+ * @kt: the struct rc_keytable descriptor
+ * @rc_map: scancode table to be searched
+ * @entry: the entry to be added to the table
+ * @resize: controls whether we are allowed to resize the table to
+ * accomodate not yet present scancodes
+ * @return: index of the mapping containing scancode in question
+ * or -1U in case of failure.
+ *
+ * This routine is used to locate given scancode in rc_map.
+ * If scancode is not yet present the routine will allocate a new slot
+ * for it.
+ */
+static unsigned int ir_establish_scancode(struct rc_keytable *kt,
+ struct rc_map *rc_map,
+ struct rc_map_table *entry,
+ bool resize)
+{
+ unsigned int i;
+
+ /*
+ * Unfortunately, some hardware-based IR decoders don't provide
+ * all bits for the complete IR code. In general, they provide only
+ * the command part of the IR code. Yet, as it is possible to replace
+ * the provided IR with another one, it is needed to allow loading
+ * IR tables from other remotes. So, we support specifying a mask to
+ * indicate the valid bits of the scancodes.
+ */
+ if (kt->dev->scanmask)
+ entry->scancode &= kt->dev->scanmask;
+
+ /*
+ * First check if we already have a mapping for this command.
+ * Note that the keytable is sorted first on protocol and second
+ * on scancode (lowest to highest).
+ */
+ for (i = 0; i < rc_map->len; i++) {
+ if (rc_map->scan[i].protocol < entry->protocol)
+ continue;
+
+ if (rc_map->scan[i].protocol > entry->protocol)
+ break;
+
+ if (rc_map->scan[i].scancode < entry->scancode)
+ continue;
+
+ if (rc_map->scan[i].scancode > entry->scancode)
+ break;
+
+ return i;
+ }
+
+ /* No previous mapping found, we might need to grow the table */
+ if (rc_map->size == rc_map->len) {
+ if (!resize || ir_resize_table(rc_map, GFP_ATOMIC))
+ return -1U;
+ }
+
+ /* i is the proper index to insert our new keycode */
+ if (i < rc_map->len)
+ memmove(&rc_map->scan[i + 1], &rc_map->scan[i],
+ (rc_map->len - i) * sizeof(struct rc_map_table));
+ rc_map->scan[i].scancode = entry->scancode;
+ rc_map->scan[i].protocol = entry->protocol;
+ rc_map->scan[i].keycode = KEY_RESERVED;
+ rc_map->len++;
+
+ return i;
+}
+
+/**
+ * ir_setkeycode() - set a keycode in the scancode->keycode table
+ * @idev: the struct input_dev device descriptor
+ * @scancode: the desired scancode
+ * @keycode: result
+ * @return: -EINVAL if the keycode could not be inserted, otherwise zero.
+ *
+ * This routine is used to handle evdev EVIOCSKEY ioctl.
+ */
+static int ir_setkeycode(struct input_dev *idev,
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
+{
+ struct rc_keytable *kt = input_get_drvdata(idev);
+ struct rc_dev *rdev = kt->dev;
+ struct rc_map *rc_map = &kt->rc_map;
+ unsigned int index;
+ struct rc_map_table entry;
+ int retval = 0;
+ unsigned long flags;
+
+ entry.keycode = ke->keycode;
+
+ spin_lock_irqsave(&rc_map->lock, flags);
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ if (index >= rc_map->len) {
+ retval = -EINVAL;
+ goto out;
+ }
+ } else if (ke->len == sizeof(int)) {
+ /* Legacy EVIOCSKEYCODE ioctl */
+ u32 scancode;
+ retval = input_scancode_to_scalar(ke, &scancode);
+ if (retval)
+ goto out;
+ entry.scancode = scancode;
+
+ /* Some heuristics to guess the correct protocol */
+ if (hweight64(rdev->enabled_protocols) == 1)
+ entry.protocol = rdev->enabled_protocols;
+ else if (hweight64(rdev->allowed_protos) == 1)
+ entry.protocol = rdev->allowed_protos;
+ else if (rc_map->len > 0)
+ entry.protocol = rc_map->scan[0].protocol;
+ else
+ entry.protocol = RC_TYPE_OTHER;
+
+ index = ir_establish_scancode(kt, rc_map, &entry, true);
+ if (index >= rc_map->len) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ } else if (ke->len == sizeof(struct rc_scancode)) {
+ /* New EVIOCSKEYCODE_V2 ioctl */
+ const struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
+ entry.protocol = rke->rc.protocol;
+ entry.scancode = rke->rc.scancode;
+
+ if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[1]) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ index = ir_establish_scancode(kt, rc_map, &entry, true);
+ if (index >= rc_map->len) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ } else {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ if (retval == 0)
+ *old_keycode = ir_update_mapping(kt, rc_map, index, ke->keycode);
+
+out:
+ spin_unlock_irqrestore(&rc_map->lock, flags);
+ return retval;
+}
+
+/**
+ * rc_setkeytable() - sets several entries in the scancode->keycode table
+ * @dev: the struct rc_dev device descriptor
+ * @to: the struct rc_map to copy entries to
+ * @from: the struct rc_map to copy entries from
+ * @return: -ENOMEM if all keycodes could not be inserted, otherwise zero.
+ *
+ * This routine is used to handle table initialization.
+ */
+static int rc_setkeytable(struct rc_keytable *kt,
+ const struct rc_map *from)
+{
+ struct rc_map *rc_map = &kt->rc_map;
+ struct rc_map_table entry;
+ unsigned int i, index;
+ int rc;
+
+ rc = ir_create_table(rc_map, from->name, from->size);
+ if (rc)
+ return rc;
+
+ IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+ rc_map->size, rc_map->alloc);
+
+ for (i = 0; i < from->size; i++) {
+ entry.protocol = from->scan[i].protocol;
+ entry.scancode = from->scan[i].scancode;
+ index = ir_establish_scancode(kt, rc_map, &entry, false);
+ if (index >= rc_map->len) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ ir_update_mapping(kt, rc_map, index, from->scan[i].keycode);
+ }
+
+ if (rc)
+ ir_free_table(rc_map);
+
+ return rc;
+}
+
+/**
+ * ir_lookup_by_scancode() - locate mapping by scancode
+ * @rc_map: the struct rc_map to search
+ * @protocol: protocol to look for in the table
+ * @scancode: scancode to look for in the table
+ * @return: index in the table, -1U if not found
+ *
+ * This routine performs binary search in RC keykeymap table for
+ * given scancode.
+ */
+static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
+ u16 protocol, u64 scancode)
+{
+ int start = 0;
+ int end = rc_map->len - 1;
+ int mid;
+ struct rc_map_table *m;
+
+ while (start <= end) {
+ mid = (start + end) / 2;
+ m = &rc_map->scan[mid];
+
+ if (m->protocol < protocol)
+ start = mid + 1;
+ else if (m->protocol > protocol)
+ end = mid - 1;
+ else if (m->scancode < scancode)
+ start = mid + 1;
+ else if (m->scancode > scancode)
+ end = mid - 1;
+ else
+ return mid;
+ }
+
+ return -1U;
+}
+
+/**
+ * ir_getkeycode() - get a keycode from the scancode->keycode table
+ * @idev: the struct input_dev device descriptor
+ * @scancode: the desired scancode
+ * @keycode: used to return the keycode, if found, or KEY_RESERVED
+ * @return: always returns zero.
+ *
+ * This routine is used to handle evdev EVIOCGKEY ioctl.
+ */
+static int ir_getkeycode(struct input_dev *idev,
+ struct input_keymap_entry *ke)
+{
+ struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
+ struct rc_keytable *kt = input_get_drvdata(idev);
+ struct rc_dev *rdev = kt->dev;
+ struct rc_map *rc_map = &kt->rc_map;
+ struct rc_map_table *entry;
+ unsigned long flags;
+ unsigned int index;
+ int retval;
+
+ spin_lock_irqsave(&rc_map->lock, flags);
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ } else if (ke->len == sizeof(int)) {
+ /* Legacy EVIOCGKEYCODE ioctl */
+ u32 scancode;
+ u16 protocol;
+
+ retval = input_scancode_to_scalar(ke, &scancode);
+ if (retval)
+ goto out;
+
+ /* Some heuristics to guess the correct protocol */
+ if (hweight64(rdev->enabled_protocols) == 1)
+ protocol = rdev->enabled_protocols;
+ else if (hweight64(rdev->allowed_protos) == 1)
+ protocol = rdev->allowed_protos;
+ else if (rc_map->len > 0)
+ protocol = rc_map->scan[0].protocol;
+ else
+ protocol = RC_TYPE_OTHER;
+
+ index = ir_lookup_by_scancode(rc_map, protocol, scancode);
+
+ } else if (ke->len == sizeof(struct rc_scancode)) {
+ /* New EVIOCGKEYCODE_V2 ioctl */
+ if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[1]) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ index = ir_lookup_by_scancode(rc_map,
+ rke->rc.protocol, rke->rc.scancode);
+
+ } else {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ if (index < rc_map->len) {
+ entry = &rc_map->scan[index];
+ ke->index = index;
+ ke->keycode = entry->keycode;
+ if (ke->len == sizeof(int)) {
+ u32 scancode = entry->scancode;
+ memcpy(ke->scancode, &scancode, sizeof(scancode));
+ } else {
+ ke->len = sizeof(struct rc_scancode);
+ rke->rc.protocol = entry->protocol;
+ rke->rc.scancode = entry->scancode;
+ }
+
+ } else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) {
+ /*
+ * We do not really know the valid range of scancodes
+ * so let's respond with KEY_RESERVED to anything we
+ * do not have mapping for [yet].
+ */
+ ke->index = index;
+ ke->keycode = KEY_RESERVED;
+ } else {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ retval = 0;
+
+out:
+ spin_unlock_irqrestore(&rc_map->lock, flags);
+ return retval;
+}
+
+/**
+ * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
+ * @dev: the struct rc_dev descriptor of the device
+ * @protocol: the protocol to look for
+ * @scancode: the scancode to look for
+ * @return: the corresponding keycode, or KEY_RESERVED
+ *
+ * This routine is used by drivers which need to convert a scancode to a
+ * keycode. Normally it should not be used since drivers should have no
+ * interest in keycodes.
+ */
+u32 rc_g_keycode_from_table(struct rc_dev *dev,
+ enum rc_type protocol, u64 scancode)
+{
+ struct rc_map *rc_map = &dev->kt->rc_map;
+ unsigned int keycode;
+ unsigned int index;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc_map->lock, flags);
+
+ index = ir_lookup_by_scancode(&dev->kt->rc_map, protocol, scancode);
+ keycode = index < rc_map->len ?
+ rc_map->scan[index].keycode : KEY_RESERVED;
+
+ spin_unlock_irqrestore(&rc_map->lock, flags);
+
+ if (keycode != KEY_RESERVED)
+ IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
+ dev->input_name, protocol,
+ (unsigned long long)scancode, keycode);
+
+ return keycode;
+}
+EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
+
+/**
+ * ir_do_keyup() - internal function to signal the release of a keypress
+ * @dev: the struct rc_dev descriptor of the device
+ * @sync: whether or not to call input_sync
+ *
+ * This function is used internally to release a keypress, it must be
+ * called with keylock held.
+ */
+static void rc_do_keyup(struct rc_keytable *kt, bool sync)
+{
+ if (!kt->keypressed)
+ return;
+
+ IR_dprintk(1, "keyup key 0x%04x\n", kt->last_keycode);
+ input_report_key(kt->idev, kt->last_keycode, 0);
+ if (sync)
+ input_sync(kt->idev);
+ kt->keypressed = false;
+}
+
+/**
+ * rc_keyup() - signals the release of a keypress
+ * @dev: the struct rc_dev descriptor of the device
+ *
+ * This routine is used to signal that a key has been released on the
+ * remote control.
+ */
+void rc_keytable_keyup(struct rc_keytable *kt)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&kt->keylock, flags);
+ rc_do_keyup(kt, true);
+ spin_unlock_irqrestore(&kt->keylock, flags);
+}
+
+/**
+ * rc_keytable_timer_keyup() - generates a keyup event after a timeout
+ * @cookie: a pointer to the struct rc_dev for the device
+ *
+ * This routine will generate a keyup event some time after a keydown event
+ * is generated when no further activity has been detected.
+ */
+static void rc_timer_keyup(unsigned long cookie)
+{
+ struct rc_keytable *kt = (struct rc_keytable *)cookie;
+ unsigned long flags;
+
+ /*
+ * keyup_jiffies is used to prevent a race condition if a
+ * hardware interrupt occurs at this point and the keyup timer
+ * event is moved further into the future as a result.
+ *
+ * The timer will then be reactivated and this function called
+ * again in the future. We need to exit gracefully in that case
+ * to allow the input subsystem to do its auto-repeat magic or
+ * a keyup event might follow immediately after the keydown.
+ */
+ spin_lock_irqsave(&kt->keylock, flags);
+ if (time_is_before_eq_jiffies(kt->keyup_jiffies))
+ rc_do_keyup(kt, true);
+ spin_unlock_irqrestore(&kt->keylock, flags);
+}
+
+/**
+ * rc_repeat() - signals that a key is still pressed
+ * @dev: the struct rc_dev descriptor of the device
+ *
+ * This routine is used by IR decoders when a repeat message which does
+ * not include the necessary bits to reproduce the scancode has been
+ * received.
+ */
+void rc_keytable_repeat(struct rc_keytable *kt)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&kt->keylock, flags);
+
+ input_event(kt->idev, EV_MSC, MSC_SCAN, kt->last_scancode);
+ input_sync(kt->idev);
+
+ if (!kt->keypressed)
+ goto out;
+
+ kt->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+ mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
+
+out:
+ spin_unlock_irqrestore(&kt->keylock, flags);
+}
+
+/**
+ * rc_keytable_keydown() - generates input event for a key press
+ * @kt: the struct rc_keytable descriptor of the keytable
+ * @protocol: the protocol for the keypress
+ * @scancode: the scancode for the keypress
+ * @toggle: the toggle value (protocol dependent, if the protocol doesn't
+ * support toggle values, this should be set to zero)
+ * @autoup: should an automatic keyup event be generated in the future
+ *
+ * This routine is used to signal that a keypress has been detected.
+ */
+void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
+ u64 scancode, u8 toggle, bool autoup)
+{
+ unsigned long flags;
+ u32 keycode;
+ bool new_event;
+
+ spin_lock_irqsave(&kt->keylock, flags);
+
+ keycode = rc_g_keycode_from_table(kt->dev, protocol, scancode);
+ new_event = !kt->keypressed || kt->last_protocol != protocol ||
+ kt->last_scancode != scancode || kt->last_toggle != toggle;
+
+ if (new_event && kt->keypressed)
+ rc_do_keyup(kt, false);
+
+ input_event(kt->idev, EV_MSC, MSC_SCAN, scancode);
+
+ if (new_event && keycode != KEY_RESERVED) {
+ /* Register a keypress */
+ kt->keypressed = true;
+ kt->last_protocol = protocol;
+ kt->last_scancode = scancode;
+ kt->last_toggle = toggle;
+ kt->last_keycode = keycode;
+
+ IR_dprintk(1, "%s: key down event, "
+ "key 0x%04x, protocol 0x%04x, scancode 0x%08llx\n",
+ kt->dev->input_name, keycode, protocol,
+ (long long unsigned)scancode);
+ input_report_key(kt->idev, keycode, 1);
+ }
+ input_sync(kt->idev);
+
+ if (autoup && kt->keypressed) {
+ kt->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+ mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
+ }
+ spin_unlock_irqrestore(&kt->keylock, flags);
+}
+
+/**
+ * rc_input_open() - called on the initial use of the input device
+ * @idev: the struct input_dev corresponding to the given keytable
+ * @return: zero on success, otherwise a negative error code
+ *
+ * This function is used by input core to signal that the input device has been
+ * opened for the first time.
+ */
+static int rc_input_open(struct input_dev *idev)
+{
+ int error;
+ struct rc_keytable *kt = input_get_drvdata(idev);
+ struct rc_dev *dev = kt->dev;
+
+ error = mutex_lock_interruptible(&dev->lock);
+ if (error)
+ return error;
+
+ if (dev->users++ == 0 && dev->open)
+ error = dev->open(dev);
+
+ mutex_unlock(&dev->lock);
+ return error;
+}
+
+/**
+ * rc_input_close() - called on the last use of the input device
+ * @idev: the struct input_dev corresponding to the given keytable
+ *
+ * This function is used by input core to signal that the last user has closed
+ * the input device.
+ */
+static void rc_input_close(struct input_dev *idev)
+{
+ struct rc_keytable *kt = input_get_drvdata(idev);
+ struct rc_dev *dev = kt->dev;
+
+ mutex_lock(&dev->lock);
+
+ if (--dev->users == 0 && dev->close)
+ dev->close(dev);
+
+ mutex_unlock(&dev->lock);
+}
+
+/**
+ * rc_keytable_create() - creates a new keytable
+ * @dev: the struct rc_dev device this keytable should belong to
+ * @map_name: the name of the keymap to autoload
+ * @return: a new struct rc_keytable pointer or NULL on error
+ *
+ * This function creates a new keytable (essentially the combination of a
+ * keytable and an input device along with some state (whether a key
+ * is currently pressed or not, etc).
+ */
+struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *map_name)
+{
+ struct rc_keytable *kt;
+ struct input_dev *idev = NULL;
+ struct rc_map *rc_map = NULL;
+ int error;
+
+ kt = kzalloc(sizeof(*kt), GFP_KERNEL);
+ if (!kt)
+ return NULL;
+
+ idev = input_allocate_device();
+ if (!idev)
+ goto out;
+
+ kt->idev = idev;
+ kt->dev = dev;
+ idev->getkeycode = ir_getkeycode;
+ idev->setkeycode = ir_setkeycode;
+ idev->open = rc_input_open;
+ idev->close = rc_input_close;
+ set_bit(EV_KEY, idev->evbit);
+ set_bit(EV_REP, idev->evbit);
+ set_bit(EV_MSC, idev->evbit);
+ set_bit(MSC_SCAN, idev->mscbit);
+ input_set_drvdata(idev, kt);
+ setup_timer(&kt->timer_keyup, rc_timer_keyup, (unsigned long)kt);
+
+ if (map_name)
+ rc_map = rc_map_get(map_name);
+ if (!rc_map)
+ rc_map = rc_map_get(RC_MAP_EMPTY);
+ if (!rc_map || !rc_map->scan || rc_map->size == 0)
+ goto out;
+
+ error = rc_setkeytable(kt, rc_map);
+ if (error)
+ goto out;
+
+ idev->dev.parent = &dev->dev;
+ memcpy(&idev->id, &dev->input_id, sizeof(dev->input_id));
+ idev->phys = dev->input_phys;
+ idev->name = dev->input_name;
+ error = input_register_device(idev);
+ if (error)
+ goto out;
+
+ /*
+ * Default delay of 250ms is too short for some protocols, especially
+ * since the timeout is currently set to 250ms. Increase it to 500ms,
+ * to avoid wrong repetition of the keycodes. Note that this must be
+ * set after the call to input_register_device().
+ */
+ idev->rep[REP_DELAY] = 500;
+
+ /*
+ * As a repeat event on protocols like RC-5 and NEC take as long as
+ * 110/114ms, using 33ms as a repeat period is not the right thing
+ * to do.
+ */
+ idev->rep[REP_PERIOD] = 125;
+
+ spin_lock_init(&kt->rc_map.lock);
+ spin_lock_init(&kt->keylock);
+ return kt;
+
+out:
+ input_free_device(idev);
+ kfree(kt);
+ return NULL;
+}
+
+/**
+ * rc_keytable_destroy() - destroys a keytable
+ * @dev: the struct rc_keytable to destroy
+ *
+ * This function destroys an existing keytable.
+ */
+void rc_keytable_destroy(struct rc_keytable *kt)
+{
+ del_timer_sync(&kt->timer_keyup);
+ /* Freeing the table should also call the stop callback */
+ ir_free_table(&kt->rc_map);
+ input_unregister_device(kt->idev);
+ kfree(kt);
+}
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index f8a63e2..83ea507 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -15,7 +15,6 @@
#include <media/rc-core.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
-#include <linux/input.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/device.h>
@@ -23,20 +22,9 @@
#include <linux/poll.h>
#include "rc-core-priv.h"
-/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
-#define IR_TAB_MIN_SIZE 256
-#define IR_TAB_MAX_SIZE 8192
-#define RC_DEV_MAX 32
-#define RC_RX_BUFFER_SIZE 1024
-
-/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
-#define IR_KEYPRESS_TIMEOUT 250
-
-/* Used to keep track of known keymaps */
-static LIST_HEAD(rc_map_list);
-static DEFINE_SPINLOCK(rc_map_lock);
-
/* Various bits and pieces to keep track of rc devices */
+#define RC_DEV_MAX 32
+#define RC_RX_BUFFER_SIZE 1024
static unsigned int rc_major;
static struct rc_dev *rc_dev_table[RC_DEV_MAX];
static DEFINE_MUTEX(rc_dev_table_mutex);
@@ -113,607 +101,6 @@ void rc_event(struct rc_dev *dev, u16 type, u16 code, u64 val)
}
EXPORT_SYMBOL_GPL(rc_event);
-static struct rc_map_list *seek_rc_map(const char *name)
-{
- struct rc_map_list *map = NULL;
-
- spin_lock(&rc_map_lock);
- list_for_each_entry(map, &rc_map_list, list) {
- if (!strcmp(name, map->map.name)) {
- spin_unlock(&rc_map_lock);
- return map;
- }
- }
- spin_unlock(&rc_map_lock);
-
- return NULL;
-}
-
-struct rc_map *rc_map_get(const char *name)
-{
-
- struct rc_map_list *map;
-
- map = seek_rc_map(name);
-#ifdef MODULE
- if (!map) {
- int rc = request_module(name);
- if (rc < 0) {
- printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
- return NULL;
- }
- msleep(20); /* Give some time for IR to register */
-
- map = seek_rc_map(name);
- }
-#endif
- if (!map) {
- printk(KERN_ERR "IR keymap %s not found\n", name);
- return NULL;
- }
-
- printk(KERN_INFO "Registered IR keymap %s\n", map->map.name);
-
- return &map->map;
-}
-EXPORT_SYMBOL_GPL(rc_map_get);
-
-int rc_map_register(struct rc_map_list *map)
-{
- spin_lock(&rc_map_lock);
- list_add_tail(&map->list, &rc_map_list);
- spin_unlock(&rc_map_lock);
- return 0;
-}
-EXPORT_SYMBOL_GPL(rc_map_register);
-
-void rc_map_unregister(struct rc_map_list *map)
-{
- spin_lock(&rc_map_lock);
- list_del(&map->list);
- spin_unlock(&rc_map_lock);
-}
-EXPORT_SYMBOL_GPL(rc_map_unregister);
-
-
-static struct rc_map_table empty[] = {
- { RC_TYPE_OTHER, 0x2a, KEY_COFFEE },
-};
-
-static struct rc_map_list empty_map = {
- .map = {
- .scan = empty,
- .size = ARRAY_SIZE(empty),
- .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
- .name = RC_MAP_EMPTY,
- }
-};
-
-/**
- * ir_create_table() - initializes a scancode table
- * @rc_map: the rc_map to initialize
- * @name: name to assign to the table
- * @size: initial size of the table
- * @return: zero on success or a negative error code
- *
- * This routine will initialize the rc_map and will allocate
- * memory to hold at least the specified number of elements.
- */
-static int ir_create_table(struct rc_map *rc_map,
- const char *name, size_t size)
-{
- rc_map->name = name;
- rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
- rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
- rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
- if (!rc_map->scan)
- return -ENOMEM;
-
- IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
- rc_map->size, rc_map->alloc);
- return 0;
-}
-
-/**
- * ir_free_table() - frees memory allocated by a scancode table
- * @rc_map: the table whose mappings need to be freed
- *
- * This routine will free memory alloctaed for key mappings used by given
- * scancode table.
- */
-static void ir_free_table(struct rc_map *rc_map)
-{
- rc_map->size = 0;
- kfree(rc_map->scan);
- rc_map->scan = NULL;
-}
-
-/**
- * ir_resize_table() - resizes a scancode table if necessary
- * @rc_map: the rc_map to resize
- * @gfp_flags: gfp flags to use when allocating memory
- * @return: zero on success or a negative error code
- *
- * This routine will shrink the rc_map if it has lots of
- * unused entries and grow it if it is full.
- */
-static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
-{
- unsigned int oldalloc = rc_map->alloc;
- unsigned int newalloc = oldalloc;
- struct rc_map_table *oldscan = rc_map->scan;
- struct rc_map_table *newscan;
-
- if (rc_map->size == rc_map->len) {
- /* All entries in use -> grow keytable */
- if (rc_map->alloc >= IR_TAB_MAX_SIZE)
- return -ENOMEM;
-
- newalloc *= 2;
- IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
- }
-
- if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
- /* Less than 1/3 of entries in use -> shrink keytable */
- newalloc /= 2;
- IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
- }
-
- if (newalloc == oldalloc)
- return 0;
-
- newscan = kmalloc(newalloc, gfp_flags);
- if (!newscan) {
- IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
- return -ENOMEM;
- }
-
- memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table));
- rc_map->scan = newscan;
- rc_map->alloc = newalloc;
- rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
- kfree(oldscan);
- return 0;
-}
-
-/**
- * ir_update_mapping() - set a keycode in the scancode->keycode table
- * @dev: the struct rc_dev device descriptor
- * @rc_map: scancode table to be adjusted
- * @index: index of the mapping that needs to be updated
- * @keycode: the desired keycode
- * @return: previous keycode assigned to the mapping
- *
- * This routine is used to update scancode->keycode mapping at given
- * position.
- */
-static unsigned int ir_update_mapping(struct rc_dev *dev,
- struct rc_map *rc_map,
- unsigned int index,
- unsigned int new_keycode)
-{
- int old_keycode = rc_map->scan[index].keycode;
- int i;
-
- /* Did the user wish to remove the mapping? */
- if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
- IR_dprintk(1, "#%d: Deleting proto 0x%04x, scan 0x%08llx\n",
- index, rc_map->scan[index].protocol,
- (unsigned long long)rc_map->scan[index].scancode);
- rc_map->len--;
- memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
- (rc_map->len - index) * sizeof(struct rc_map_table));
- } else {
- IR_dprintk(1, "#%d: %s proto 0x%04x, scan 0x%08llx "
- "with key 0x%04x\n",
- index,
- old_keycode == KEY_RESERVED ? "New" : "Replacing",
- rc_map->scan[index].protocol,
- (unsigned long long)rc_map->scan[index].scancode,
- new_keycode);
- rc_map->scan[index].keycode = new_keycode;
- __set_bit(new_keycode, dev->input_dev->keybit);
- }
-
- if (old_keycode != KEY_RESERVED) {
- /* A previous mapping was updated... */
- __clear_bit(old_keycode, dev->input_dev->keybit);
- /* ... but another scancode might use the same keycode */
- for (i = 0; i < rc_map->len; i++) {
- if (rc_map->scan[i].keycode == old_keycode) {
- __set_bit(old_keycode, dev->input_dev->keybit);
- break;
- }
- }
-
- /* Possibly shrink the keytable, failure is not a problem */
- ir_resize_table(rc_map, GFP_ATOMIC);
- }
-
- return old_keycode;
-}
-
-/**
- * ir_establish_scancode() - set a keycode in the scancode->keycode table
- * @dev: the struct rc_dev device descriptor
- * @rc_map: scancode table to be searched
- * @entry: the entry to be added to the table
- * @resize: controls whether we are allowed to resize the table to
- * accomodate not yet present scancodes
- * @return: index of the mapping containing scancode in question
- * or -1U in case of failure.
- *
- * This routine is used to locate given scancode in rc_map.
- * If scancode is not yet present the routine will allocate a new slot
- * for it.
- */
-static unsigned int ir_establish_scancode(struct rc_dev *dev,
- struct rc_map *rc_map,
- struct rc_map_table *entry,
- bool resize)
-{
- unsigned int i;
-
- /*
- * Unfortunately, some hardware-based IR decoders don't provide
- * all bits for the complete IR code. In general, they provide only
- * the command part of the IR code. Yet, as it is possible to replace
- * the provided IR with another one, it is needed to allow loading
- * IR tables from other remotes. So, we support specifying a mask to
- * indicate the valid bits of the scancodes.
- */
- if (dev->scanmask)
- entry->scancode &= dev->scanmask;
-
- /*
- * First check if we already have a mapping for this command.
- * Note that the keytable is sorted first on protocol and second
- * on scancode (lowest to highest).
- */
- for (i = 0; i < rc_map->len; i++) {
- if (rc_map->scan[i].protocol < entry->protocol)
- continue;
-
- if (rc_map->scan[i].protocol > entry->protocol)
- break;
-
- if (rc_map->scan[i].scancode < entry->scancode)
- continue;
-
- if (rc_map->scan[i].scancode > entry->scancode)
- break;
-
- return i;
- }
-
- /* No previous mapping found, we might need to grow the table */
- if (rc_map->size == rc_map->len) {
- if (!resize || ir_resize_table(rc_map, GFP_ATOMIC))
- return -1U;
- }
-
- /* i is the proper index to insert our new keycode */
- if (i < rc_map->len)
- memmove(&rc_map->scan[i + 1], &rc_map->scan[i],
- (rc_map->len - i) * sizeof(struct rc_map_table));
- rc_map->scan[i].scancode = entry->scancode;
- rc_map->scan[i].protocol = entry->protocol;
- rc_map->scan[i].keycode = KEY_RESERVED;
- rc_map->len++;
-
- return i;
-}
-
-/**
- * ir_setkeycode() - set a keycode in the scancode->keycode table
- * @idev: the struct input_dev device descriptor
- * @scancode: the desired scancode
- * @keycode: result
- * @return: -EINVAL if the keycode could not be inserted, otherwise zero.
- *
- * This routine is used to handle evdev EVIOCSKEY ioctl.
- */
-static int ir_setkeycode(struct input_dev *idev,
- const struct input_keymap_entry *ke,
- unsigned int *old_keycode)
-{
- struct rc_dev *rdev = input_get_drvdata(idev);
- struct rc_map *rc_map = &rdev->rc_map;
- unsigned int index;
- struct rc_map_table entry;
- int retval = 0;
- unsigned long flags;
-
- entry.keycode = ke->keycode;
-
- spin_lock_irqsave(&rc_map->lock, flags);
-
- if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
- index = ke->index;
- if (index >= rc_map->len) {
- retval = -EINVAL;
- goto out;
- }
- } else if (ke->len == sizeof(int)) {
- /* Legacy EVIOCSKEYCODE ioctl */
- u32 scancode;
- retval = input_scancode_to_scalar(ke, &scancode);
- if (retval)
- goto out;
- entry.scancode = scancode;
-
- /* Some heuristics to guess the correct protocol */
- if (hweight64(rdev->enabled_protocols) == 1)
- entry.protocol = rdev->enabled_protocols;
- else if (hweight64(rdev->allowed_protos) == 1)
- entry.protocol = rdev->allowed_protos;
- else if (rc_map->len > 0)
- entry.protocol = rc_map->scan[0].protocol;
- else
- entry.protocol = RC_TYPE_OTHER;
-
- index = ir_establish_scancode(rdev, rc_map, &entry, true);
- if (index >= rc_map->len) {
- retval = -ENOMEM;
- goto out;
- }
- } else if (ke->len == sizeof(struct rc_scancode)) {
- /* New EVIOCSKEYCODE_V2 ioctl */
- const struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
- entry.protocol = rke->rc.protocol;
- entry.scancode = rke->rc.scancode;
-
- if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[1]) {
- retval = -EINVAL;
- goto out;
- }
-
- index = ir_establish_scancode(rdev, rc_map, &entry, true);
- if (index >= rc_map->len) {
- retval = -ENOMEM;
- goto out;
- }
- } else {
- retval = -EINVAL;
- goto out;
- }
-
- if (retval == 0)
- *old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode);
-
-out:
- spin_unlock_irqrestore(&rc_map->lock, flags);
- return retval;
-}
-
-/**
- * ir_setkeytable() - sets several entries in the scancode->keycode table
- * @dev: the struct rc_dev device descriptor
- * @to: the struct rc_map to copy entries to
- * @from: the struct rc_map to copy entries from
- * @return: -ENOMEM if all keycodes could not be inserted, otherwise zero.
- *
- * This routine is used to handle table initialization.
- */
-static int ir_setkeytable(struct rc_dev *dev,
- const struct rc_map *from)
-{
- struct rc_map *rc_map = &dev->rc_map;
- struct rc_map_table entry;
- unsigned int i, index;
- int rc;
-
- rc = ir_create_table(rc_map, from->name, from->size);
- if (rc)
- return rc;
-
- IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
- rc_map->size, rc_map->alloc);
-
- for (i = 0; i < from->size; i++) {
- entry.protocol = from->scan[i].protocol;
- entry.scancode = from->scan[i].scancode;
- index = ir_establish_scancode(dev, rc_map, &entry, false);
- if (index >= rc_map->len) {
- rc = -ENOMEM;
- break;
- }
-
- ir_update_mapping(dev, rc_map, index, from->scan[i].keycode);
- }
-
- if (rc)
- ir_free_table(rc_map);
-
- return rc;
-}
-
-/**
- * ir_lookup_by_scancode() - locate mapping by scancode
- * @rc_map: the struct rc_map to search
- * @protocol: protocol to look for in the table
- * @scancode: scancode to look for in the table
- * @return: index in the table, -1U if not found
- *
- * This routine performs binary search in RC keykeymap table for
- * given scancode.
- */
-static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
- u16 protocol, u64 scancode)
-{
- int start = 0;
- int end = rc_map->len - 1;
- int mid;
- struct rc_map_table *m;
-
- while (start <= end) {
- mid = (start + end) / 2;
- m = &rc_map->scan[mid];
-
- if (m->protocol < protocol)
- start = mid + 1;
- else if (m->protocol > protocol)
- end = mid - 1;
- else if (m->scancode < scancode)
- start = mid + 1;
- else if (m->scancode > scancode)
- end = mid - 1;
- else
- return mid;
- }
-
- return -1U;
-}
-
-/**
- * ir_getkeycode() - get a keycode from the scancode->keycode table
- * @idev: the struct input_dev device descriptor
- * @scancode: the desired scancode
- * @keycode: used to return the keycode, if found, or KEY_RESERVED
- * @return: always returns zero.
- *
- * This routine is used to handle evdev EVIOCGKEY ioctl.
- */
-static int ir_getkeycode(struct input_dev *idev,
- struct input_keymap_entry *ke)
-{
- struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
- struct rc_dev *rdev = input_get_drvdata(idev);
- struct rc_map *rc_map = &rdev->rc_map;
- struct rc_map_table *entry;
- unsigned long flags;
- unsigned int index;
- int retval;
-
- spin_lock_irqsave(&rc_map->lock, flags);
-
- if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
- index = ke->index;
- } else if (ke->len == sizeof(int)) {
- /* Legacy EVIOCGKEYCODE ioctl */
- u32 scancode;
- u16 protocol;
-
- retval = input_scancode_to_scalar(ke, &scancode);
- if (retval)
- goto out;
-
- /* Some heuristics to guess the correct protocol */
- if (hweight64(rdev->enabled_protocols) == 1)
- protocol = rdev->enabled_protocols;
- else if (hweight64(rdev->allowed_protos) == 1)
- protocol = rdev->allowed_protos;
- else if (rc_map->len > 0)
- protocol = rc_map->scan[0].protocol;
- else
- protocol = RC_TYPE_OTHER;
-
- index = ir_lookup_by_scancode(rc_map, protocol, scancode);
-
- } else if (ke->len == sizeof(struct rc_scancode)) {
- /* New EVIOCGKEYCODE_V2 ioctl */
- if (rke->rc.reserved[0] || rke->rc.reserved[1] || rke->rc.reserved[1]) {
- retval = -EINVAL;
- goto out;
- }
-
- index = ir_lookup_by_scancode(rc_map,
- rke->rc.protocol, rke->rc.scancode);
-
- } else {
- retval = -EINVAL;
- goto out;
- }
-
- if (index < rc_map->len) {
- entry = &rc_map->scan[index];
- ke->index = index;
- ke->keycode = entry->keycode;
- if (ke->len == sizeof(int)) {
- u32 scancode = entry->scancode;
- memcpy(ke->scancode, &scancode, sizeof(scancode));
- } else {
- ke->len = sizeof(struct rc_scancode);
- rke->rc.protocol = entry->protocol;
- rke->rc.scancode = entry->scancode;
- }
-
- } else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) {
- /*
- * We do not really know the valid range of scancodes
- * so let's respond with KEY_RESERVED to anything we
- * do not have mapping for [yet].
- */
- ke->index = index;
- ke->keycode = KEY_RESERVED;
- } else {
- retval = -EINVAL;
- goto out;
- }
-
- retval = 0;
-
-out:
- spin_unlock_irqrestore(&rc_map->lock, flags);
- return retval;
-}
-
-/**
- * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
- * @dev: the struct rc_dev descriptor of the device
- * @protocol: the protocol to look for
- * @scancode: the scancode to look for
- * @return: the corresponding keycode, or KEY_RESERVED
- *
- * This routine is used by drivers which need to convert a scancode to a
- * keycode. Normally it should not be used since drivers should have no
- * interest in keycodes.
- */
-u32 rc_g_keycode_from_table(struct rc_dev *dev,
- enum rc_type protocol, u64 scancode)
-{
- struct rc_map *rc_map = &dev->rc_map;
- unsigned int keycode;
- unsigned int index;
- unsigned long flags;
-
- spin_lock_irqsave(&rc_map->lock, flags);
-
- index = ir_lookup_by_scancode(rc_map, protocol, scancode);
- keycode = index < rc_map->len ?
- rc_map->scan[index].keycode : KEY_RESERVED;
-
- spin_unlock_irqrestore(&rc_map->lock, flags);
-
- if (keycode != KEY_RESERVED)
- IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
- dev->input_name, protocol,
- (unsigned long long)scancode, keycode);
-
- return keycode;
-}
-EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
-
-/**
- * ir_do_keyup() - internal function to signal the release of a keypress
- * @dev: the struct rc_dev descriptor of the device
- * @sync: whether or not to call input_sync
- *
- * This function is used internally to release a keypress, it must be
- * called with keylock held.
- */
-static void ir_do_keyup(struct rc_dev *dev, bool sync)
-{
- if (!dev->keypressed)
- return;
-
- IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
- input_report_key(dev->input_dev, dev->last_keycode, 0);
- if (sync)
- input_sync(dev->input_dev);
- dev->keypressed = false;
-}
-
/**
* rc_keyup() - signals the release of a keypress
* @dev: the struct rc_dev descriptor of the device
@@ -723,43 +110,11 @@ static void ir_do_keyup(struct rc_dev *dev, bool sync)
*/
void rc_keyup(struct rc_dev *dev)
{
- unsigned long flags;
-
- spin_lock_irqsave(&dev->keylock, flags);
- ir_do_keyup(dev, true);
- spin_unlock_irqrestore(&dev->keylock, flags);
+ rc_keytable_keyup(dev->kt);
}
EXPORT_SYMBOL_GPL(rc_keyup);
/**
- * ir_timer_keyup() - generates a keyup event after a timeout
- * @cookie: a pointer to the struct rc_dev for the device
- *
- * This routine will generate a keyup event some time after a keydown event
- * is generated when no further activity has been detected.
- */
-static void ir_timer_keyup(unsigned long cookie)
-{
- struct rc_dev *dev = (struct rc_dev *)cookie;
- unsigned long flags;
-
- /*
- * ir->keyup_jiffies is used to prevent a race condition if a
- * hardware interrupt occurs at this point and the keyup timer
- * event is moved further into the future as a result.
- *
- * The timer will then be reactivated and this function called
- * again in the future. We need to exit gracefully in that case
- * to allow the input subsystem to do its auto-repeat magic or
- * a keyup event might follow immediately after the keydown.
- */
- spin_lock_irqsave(&dev->keylock, flags);
- if (time_is_before_eq_jiffies(dev->keyup_jiffies))
- ir_do_keyup(dev, true);
- spin_unlock_irqrestore(&dev->keylock, flags);
-}
-
-/**
* rc_repeat() - signals that a key is still pressed
* @dev: the struct rc_dev descriptor of the device
*
@@ -769,135 +124,32 @@ static void ir_timer_keyup(unsigned long cookie)
*/
void rc_repeat(struct rc_dev *dev)
{
- unsigned long flags;
-
- spin_lock_irqsave(&dev->keylock, flags);
-
- input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
- input_sync(dev->input_dev);
+ rc_keytable_repeat(dev->kt);
rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
-
- if (!dev->keypressed)
- goto out;
-
- dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
- mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
-
-out:
- spin_unlock_irqrestore(&dev->keylock, flags);
}
EXPORT_SYMBOL_GPL(rc_repeat);
/**
- * ir_do_keydown() - internal function to process a keypress
- * @dev: the struct rc_dev descriptor of the device
- * @protocol: the protocol of the keypress
- * @scancode: the scancode of the keypress
- * @keycode: the keycode of the keypress
- * @toggle: the toggle value of the keypress
- *
- * This function is used internally to register a keypress, it must be
- * called with keylock held.
- */
-static void ir_do_keydown(struct rc_dev *dev, u16 protocol,
- u64 scancode, u32 keycode, u8 toggle)
-{
- bool new_event = !dev->keypressed ||
- dev->last_protocol != protocol ||
- dev->last_scancode != scancode ||
- dev->last_toggle != toggle;
-
- if (new_event && dev->keypressed)
- ir_do_keyup(dev, false);
-
- input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
- rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
- rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
- rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
-
- if (new_event && keycode != KEY_RESERVED) {
- /* Register a keypress */
- dev->keypressed = true;
- dev->last_protocol = protocol;
- dev->last_scancode = scancode;
- dev->last_toggle = toggle;
- dev->last_keycode = keycode;
-
- IR_dprintk(1, "%s: key down event, "
- "key 0x%04x, protocol 0x%04x, scancode 0x%08llx\n",
- dev->input_name, keycode, protocol,
- (long long unsigned)scancode);
- input_report_key(dev->input_dev, keycode, 1);
- }
- input_sync(dev->input_dev);
-}
-
-/**
- * rc_keydown() - generates input event for a key press
+ * rc_do_keydown() - generates input event for a key press
* @dev: the struct rc_dev descriptor of the device
* @protocol: the protocol for the keypress
* @scancode: the scancode for the keypress
* @toggle: the toggle value (protocol dependent, if the protocol doesn't
* support toggle values, this should be set to zero)
+ * @autoup: should an automatic keyup event be generated in the future
*
* This routine is used to signal that a key has been pressed on the
* remote control.
*/
-void rc_keydown(struct rc_dev *dev, enum rc_type protocol,
- u64 scancode, u8 toggle)
-{
- unsigned long flags;
- u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
-
- spin_lock_irqsave(&dev->keylock, flags);
- ir_do_keydown(dev, protocol, scancode, keycode, toggle);
-
- if (dev->keypressed) {
- dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
- mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
- }
- spin_unlock_irqrestore(&dev->keylock, flags);
-}
-EXPORT_SYMBOL_GPL(rc_keydown);
-
-/**
- * rc_keydown_notimeout() - generates input event for a key press without
- * an automatic keyup event at a later time
- * @dev: the struct rc_dev descriptor of the device
- * @protocol: the protocol for the keypress
- * @scancode: the scancode that we're seeking
- * @toggle: the toggle value (protocol dependent, if the protocol doesn't
- * support toggle values, this should be set to zero)
- *
- * This routine is used to signal that a key has been pressed on the
- * remote control. The driver must manually call rc_keyup() at a later stage.
- */
-void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
- u64 scancode, u8 toggle)
-{
- unsigned long flags;
- u32 keycode = rc_g_keycode_from_table(dev, protocol, scancode);
-
- spin_lock_irqsave(&dev->keylock, flags);
- ir_do_keydown(dev, protocol, scancode, keycode, toggle);
- spin_unlock_irqrestore(&dev->keylock, flags);
-}
-EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
-
-static int ir_open(struct input_dev *idev)
-{
- struct rc_dev *rdev = input_get_drvdata(idev);
-
- return rdev->open(rdev);
-}
-
-static void ir_close(struct input_dev *idev)
+void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol,
+ u64 scancode, u8 toggle, bool autoup)
{
- struct rc_dev *rdev = input_get_drvdata(idev);
-
- if (rdev)
- rdev->close(rdev);
+ rc_keytable_keydown(dev->kt, protocol, scancode, toggle, autoup);
+ rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
+ rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
+ rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
}
+EXPORT_SYMBOL_GPL(rc_do_keydown);
/* class for /sys/class/rc */
static char *rc_devnode(struct device *dev, umode_t *mode)
@@ -1132,9 +384,6 @@ static void rc_dev_release(struct device *device)
{
struct rc_dev *dev = to_rc_dev(device);
- if (dev->input_dev)
- input_free_device(dev->input_dev);
-
kfifo_free(&dev->txfifo);
kfree(dev);
module_put(THIS_MODULE);
@@ -1151,11 +400,11 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
{
struct rc_dev *dev = to_rc_dev(device);
- if (!dev || !dev->input_dev)
+ if (!dev)
return -ENODEV;
- if (dev->rc_map.name)
- ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name);
+ if (dev->map_name)
+ ADD_HOTPLUG_VAR("NAME=%s", dev->map_name);
if (dev->driver_name)
ADD_HOTPLUG_VAR("DRV_NAME=%s", dev->driver_name);
@@ -1196,26 +445,14 @@ struct rc_dev *rc_allocate_device(void)
if (!dev)
return NULL;
- dev->input_dev = input_allocate_device();
- if (!dev->input_dev) {
- kfree(dev);
- return NULL;
- }
-
- dev->input_dev->getkeycode = ir_getkeycode;
- dev->input_dev->setkeycode = ir_setkeycode;
- input_set_drvdata(dev->input_dev, dev);
-
INIT_LIST_HEAD(&dev->client_list);
spin_lock_init(&dev->client_lock);
INIT_KFIFO(dev->txfifo);
spin_lock_init(&dev->txlock);
init_waitqueue_head(&dev->rxwait);
init_waitqueue_head(&dev->txwait);
- spin_lock_init(&dev->rc_map.lock);
- spin_lock_init(&dev->keylock);
+ spin_lock_init(&dev->txlock);
mutex_init(&dev->lock);
- setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev);
dev->dev.type = &rc_dev_type;
dev->dev.class = &rc_class;
@@ -1244,7 +481,6 @@ EXPORT_SYMBOL_GPL(rc_free_device);
int rc_register_device(struct rc_dev *dev)
{
static bool raw_init = false; /* raw decoders loaded? */
- struct rc_map *rc_map;
const char *path;
int rc;
unsigned int i;
@@ -1252,21 +488,6 @@ int rc_register_device(struct rc_dev *dev)
if (!dev || !dev->map_name)
return -EINVAL;
- rc_map = rc_map_get(dev->map_name);
- if (!rc_map)
- rc_map = rc_map_get(RC_MAP_EMPTY);
- if (!rc_map || !rc_map->scan || rc_map->size == 0)
- return -EINVAL;
-
- set_bit(EV_KEY, dev->input_dev->evbit);
- set_bit(EV_REP, dev->input_dev->evbit);
- set_bit(EV_MSC, dev->input_dev->evbit);
- set_bit(MSC_SCAN, dev->input_dev->mscbit);
- if (dev->open)
- dev->input_dev->open = ir_open;
- if (dev->close)
- dev->input_dev->close = ir_close;
-
rc = mutex_lock_interruptible(&rc_dev_table_mutex);
if (rc)
return rc;
@@ -1303,36 +524,15 @@ int rc_register_device(struct rc_dev *dev)
*/
mutex_lock(&dev->lock);
- rc = device_add(&dev->dev);
- if (rc)
+ dev->kt = rc_keytable_create(dev, dev->map_name);
+ if (!dev->kt) {
+ rc = -ENOMEM;
goto out_unlock;
+ }
- rc = ir_setkeytable(dev, rc_map);
- if (rc)
- goto out_dev;
-
- dev->input_dev->dev.parent = &dev->dev;
- memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id));
- dev->input_dev->phys = dev->input_phys;
- dev->input_dev->name = dev->input_name;
- rc = input_register_device(dev->input_dev);
+ rc = device_add(&dev->dev);
if (rc)
- goto out_table;
-
- /*
- * Default delay of 250ms is too short for some protocols, especially
- * since the timeout is currently set to 250ms. Increase it to 500ms,
- * to avoid wrong repetition of the keycodes. Note that this must be
- * set after the call to input_register_device().
- */
- dev->input_dev->rep[REP_DELAY] = 500;
-
- /*
- * As a repeat event on protocols like RC-5 and NEC take as long as
- * 110/114ms, using 33ms as a repeat period is not the right thing
- * to do.
- */
- dev->input_dev->rep[REP_PERIOD] = 125;
+ goto out_keytable;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
printk(KERN_INFO "%s: %s as %s\n",
@@ -1350,7 +550,7 @@ int rc_register_device(struct rc_dev *dev)
}
rc = ir_raw_event_register(dev);
if (rc < 0)
- goto out_input;
+ goto out_dev;
}
if (dev->change_protocol) {
@@ -1365,7 +565,7 @@ int rc_register_device(struct rc_dev *dev)
IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n",
dev->minor,
dev->driver_name ? dev->driver_name : "unknown",
- rc_map->name ? rc_map->name : "unknown",
+ dev->map_name ? dev->map_name : "unknown",
dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
return 0;
@@ -1373,13 +573,10 @@ int rc_register_device(struct rc_dev *dev)
out_raw:
if (dev->driver_type == RC_DRIVER_IR_RAW)
ir_raw_event_unregister(dev);
-out_input:
- input_unregister_device(dev->input_dev);
- dev->input_dev = NULL;
-out_table:
- ir_free_table(&dev->rc_map);
out_dev:
device_del(&dev->dev);
+out_keytable:
+ rc_keytable_destroy(dev->kt);
out_unlock:
mutex_unlock(&dev->lock);
out_minor:
@@ -1412,18 +609,10 @@ void rc_unregister_device(struct rc_dev *dev)
wake_up_interruptible_all(&dev->rxwait);
wake_up_interruptible_all(&dev->txwait);
- del_timer_sync(&dev->timer_keyup);
-
if (dev->driver_type == RC_DRIVER_IR_RAW)
ir_raw_event_unregister(dev);
- /* Freeing the table should also call the stop callback */
- ir_free_table(&dev->rc_map);
- IR_dprintk(1, "Freed keycode table\n");
-
- input_unregister_device(dev->input_dev);
- dev->input_dev = NULL;
-
+ rc_keytable_destroy(dev->kt);
device_unregister(&dev->dev);
}
@@ -1480,6 +669,9 @@ static int rc_open(struct inode *inode, struct file *file)
file->private_data = client;
nonseekable_open(inode, file);
+ if (dev->users++ == 0 && dev->open)
+ dev->open(dev);
+
IR_dprintk(2, "Device %u opened\n", iminor(inode));
return 0;
@@ -1507,6 +699,10 @@ static int rc_release(struct inode *inode, struct file *file)
spin_unlock(&dev->client_lock);
synchronize_rcu();
kfree(client);
+
+ if (--dev->users == 0 && dev->close)
+ dev->close(dev);
+
put_device(&dev->dev);
IR_dprintk(2, "Device %u closed\n", iminor(inode));
@@ -1819,6 +1015,19 @@ static const struct file_operations rc_fops = {
#endif
};
+static struct rc_map_table empty[] = {
+ { RC_TYPE_OTHER, 0x2a, KEY_COFFEE },
+};
+
+static struct rc_map_list empty_map = {
+ .map = {
+ .scan = empty,
+ .size = ARRAY_SIZE(empty),
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .name = RC_MAP_EMPTY,
+ }
+};
+
static int __init rc_core_init(void)
{
int ret;
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 843f363..20bd1ce 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -262,32 +262,24 @@ struct rc_dev {
struct input_id input_id;
char *driver_name;
const char *map_name;
- struct rc_map rc_map;
+ struct rc_keytable *kt;
struct mutex lock;
unsigned int minor;
bool exist;
struct list_head client_list;
spinlock_t client_lock;
+ unsigned users;
DECLARE_KFIFO_PTR(txfifo, struct ir_raw_event);
spinlock_t txlock;
wait_queue_head_t txwait;
wait_queue_head_t rxwait;
struct ir_raw_event_ctrl *raw;
- struct input_dev *input_dev;
enum rc_driver_type driver_type;
bool idle;
u64 allowed_protos;
u64 enabled_protocols;
u32 scanmask;
void *priv;
- spinlock_t keylock;
- bool keypressed;
- unsigned long keyup_jiffies;
- struct timer_list timer_keyup;
- u32 last_keycode;
- enum rc_type last_protocol;
- u64 last_scancode;
- u8 last_toggle;
u32 timeout;
u32 min_timeout;
u32 max_timeout;
@@ -310,6 +302,34 @@ struct rc_dev {
int (*set_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
};
+/**
+ * struct rc_keytable - represents one keytable for a rc_dev device
+ * @dev: the rc_dev device this keytable belongs to
+ * @idev: the input_dev device which belongs to this keytable
+ * @rc_map: holds the scancode <-> keycode mappings
+ * @keypressed: whether a key is currently pressed or not
+ * @keyup_jiffies: when the key should be auto-released
+ * @timer_keyup: responsible for the auto-release of keys
+ * @keylock: protects the key state
+ * @last_keycode: keycode of the last keypress
+ * @last_protocol: protocol of the last keypress
+ * @last_scancode: scancode of the last keypress
+ * @last_toggle: toggle of the last keypress
+ */
+struct rc_keytable {
+ struct rc_dev *dev;
+ struct input_dev *idev;
+ struct rc_map rc_map;
+ bool keypressed;
+ unsigned long keyup_jiffies;
+ struct timer_list timer_keyup;
+ spinlock_t keylock;
+ u32 last_keycode;
+ enum rc_type last_protocol;
+ u64 last_scancode;
+ u8 last_toggle;
+};
+
#define to_rc_dev(d) container_of(d, struct rc_dev, dev)
/* rc_event.type value */
@@ -354,9 +374,10 @@ void rc_unregister_device(struct rc_dev *dev);
void rc_event(struct rc_dev *dev, u16 type, u16 code, u64 val);
void rc_repeat(struct rc_dev *dev);
-void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u64 scancode, u8 toggle);
-void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol, u64 scancode, u8 toggle);
void rc_keyup(struct rc_dev *dev);
+void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol, u64 scancode, u8 toggle, bool autoup);
+#define rc_keydown(dev, proto, scan, toggle) rc_do_keydown(dev, proto, scan, toggle, true)
+#define rc_keydown_notimeout(dev, proto, scan, toggle) rc_do_keydown(dev, proto, scan, toggle, false)
u32 rc_g_keycode_from_table(struct rc_dev *dev, enum rc_type protocol, u64 scancode);
/*
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 26/43] rc-core: do not take mutex on rc_dev registration
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (24 preceding siblings ...)
2012-05-23 9:44 ` [PATCH 25/43] rc-core: prepare for multiple keytables David Härdeman
@ 2012-05-23 9:44 ` David Härdeman
2012-05-23 9:44 ` [PATCH 27/43] rc-core: make the keytable of rc_dev an array David Härdeman
` (17 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:44 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Change the rc_register_device() code so that it isn't necessary to hold any
mutex. When device_add() is called, the norm is that the device should
actually be ready for use.
Holding the mutex is a recipe for deadlocks as (for example) calling
input_register_device() is quite likely to end up in a call to
input_dev->open() which might take the same mutex (to update the user
count, see later patches).
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-main.c | 95 ++++++++++++++++++--------------------------
include/media/rc-core.h | 3 -
2 files changed, 40 insertions(+), 58 deletions(-)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 83ea507..620cd8d 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -214,8 +214,8 @@ static struct {
* It returns the protocol names of supported protocols.
* Enabled protocols are printed in brackets.
*
- * dev->lock is taken to guard against races between device
- * registration, store_protocols and show_protocols.
+ * dev->lock is taken to guard against races between store_protocols
+ * and show_protocols.
*/
static ssize_t show_protocols(struct device *device,
struct device_attribute *mattr, char *buf)
@@ -276,8 +276,8 @@ static ssize_t show_protocols(struct device *device,
* Returns -EINVAL if an invalid protocol combination or unknown protocol name
* is used, otherwise @len.
*
- * dev->lock is taken to guard against races between device
- * registration, store_protocols and show_protocols.
+ * dev->lock is taken to guard against races between store_protocols and
+ * show_protocols.
*/
static ssize_t store_protocols(struct device *device,
struct device_attribute *mattr,
@@ -492,17 +492,14 @@ int rc_register_device(struct rc_dev *dev)
if (rc)
return rc;
- for (i = 0; i < ARRAY_SIZE(rc_dev_table); i++) {
- if (!rc_dev_table[i]) {
- rc_dev_table[i] = dev;
+ for (i = 0; i < ARRAY_SIZE(rc_dev_table); i++)
+ if (!rc_dev_table[i])
break;
- }
- }
-
- mutex_unlock(&rc_dev_table_mutex);
- if (i >= ARRAY_SIZE(rc_dev_table))
- return -ENFILE;
+ if (i >= ARRAY_SIZE(rc_dev_table)) {
+ rc = -ENFILE;
+ goto out;
+ }
dev->minor = i;
dev->dev.devt = MKDEV(rc_major, dev->minor);
@@ -512,35 +509,9 @@ int rc_register_device(struct rc_dev *dev)
if (dev->tx_ir) {
rc = kfifo_alloc(&dev->txfifo, RC_TX_KFIFO_SIZE, GFP_KERNEL);
if (rc)
- goto out_minor;
- }
-
- /*
- * Take the lock here, as the device sysfs node will appear
- * when device_add() is called, which may trigger an ir-keytable udev
- * rule, which will in turn call show_protocols and access either
- * dev->rc_map.rc_type or dev->raw->enabled_protocols before it has
- * been initialized.
- */
- mutex_lock(&dev->lock);
-
- dev->kt = rc_keytable_create(dev, dev->map_name);
- if (!dev->kt) {
- rc = -ENOMEM;
- goto out_unlock;
+ goto out;
}
- rc = device_add(&dev->dev);
- if (rc)
- goto out_keytable;
-
- path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
- printk(KERN_INFO "%s: %s as %s\n",
- dev_name(&dev->dev),
- dev->input_name ? dev->input_name : "Unspecified device",
- path ? path : "N/A");
- kfree(path);
-
if (dev->driver_type == RC_DRIVER_IR_RAW) {
/* Load raw decoders, if they aren't already */
if (!raw_init) {
@@ -550,7 +521,7 @@ int rc_register_device(struct rc_dev *dev)
}
rc = ir_raw_event_register(dev);
if (rc < 0)
- goto out_dev;
+ goto out_kfifo;
}
if (dev->change_protocol) {
@@ -559,29 +530,41 @@ int rc_register_device(struct rc_dev *dev)
goto out_raw;
}
+ rc_dev_table[i] = dev;
dev->exist = true;
- mutex_unlock(&dev->lock);
- IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n",
- dev->minor,
- dev->driver_name ? dev->driver_name : "unknown",
- dev->map_name ? dev->map_name : "unknown",
- dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
+ /* Once device_add is called, userspace might access e.g. sysfs files */
+ rc = device_add(&dev->dev);
+ if (rc)
+ goto out_chardev;
+
+ dev->kt = rc_keytable_create(dev, dev->map_name);
+ if (!dev->kt) {
+ rc = -ENOMEM;
+ goto out_device;
+ }
+
+ mutex_unlock(&rc_dev_table_mutex);
+
+ path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
+ printk(KERN_INFO "%s: %s as %s\n",
+ dev_name(&dev->dev),
+ dev->input_name ? dev->input_name : "Unspecified device",
+ path ? path : "N/A");
+ kfree(path);
return 0;
+out_device:
+ device_del(&dev->dev);
+out_chardev:
+ rc_dev_table[dev->minor] = NULL;
out_raw:
if (dev->driver_type == RC_DRIVER_IR_RAW)
ir_raw_event_unregister(dev);
-out_dev:
- device_del(&dev->dev);
-out_keytable:
- rc_keytable_destroy(dev->kt);
-out_unlock:
- mutex_unlock(&dev->lock);
-out_minor:
- mutex_lock(&rc_dev_table_mutex);
- rc_dev_table[dev->minor] = NULL;
+out_kfifo:
+ kfifo_free(&dev->txfifo);
+out:
mutex_unlock(&rc_dev_table_mutex);
return rc;
}
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 20bd1ce..e34815b 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -203,8 +203,7 @@ struct ir_raw_event {
* @driver_name: name of the hardware driver which registered this device
* @map_name: name of the default keymap
* @rc_map: current scan/key table
- * @lock: used to ensure we've filled in all protocol details before
- * anyone can call show_protocols or store_protocols
+ * @lock: used where a more specific lock/mutex/etc is not available
* @minor: unique minor remote control device number
* @exist: used to determine if the device is still valid
* @client_list: list of clients (processes which have opened the rc chardev)
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 27/43] rc-core: make the keytable of rc_dev an array
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (25 preceding siblings ...)
2012-05-23 9:44 ` [PATCH 26/43] rc-core: do not take mutex on rc_dev registration David Härdeman
@ 2012-05-23 9:44 ` David Härdeman
2012-05-23 9:44 ` [PATCH 28/43] rc-core: add ioctls for adding/removing keytables from userspace David Härdeman
` (16 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:44 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
This is another step towards allowing multiple keytables per rc_dev.
struct rc_dev is changed to hold an array of keytables (used later for
indexed access to keytables) as well as a list of the same keytables
(used for iteration in fast paths).
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-keytable.c | 61 ++++++++++++++++++++++++----------
drivers/media/rc/rc-main.c | 71 +++++++++++++++++++++++++++++++++++-----
include/media/rc-core.h | 6 +++
3 files changed, 110 insertions(+), 28 deletions(-)
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index 7096f44..f422a3b 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -568,6 +568,35 @@ out:
return retval;
}
+static u32 rc_get_keycode(struct rc_keytable *kt,
+ enum rc_type protocol, u64 scancode)
+{
+ struct rc_map *rc_map;
+ unsigned int keycode = KEY_RESERVED;
+ unsigned int index;
+ unsigned long flags;
+
+ rc_map = &kt->rc_map;
+ if (!rc_map)
+ return KEY_RESERVED;
+
+ spin_lock_irqsave(&rc_map->lock, flags);
+
+ index = ir_lookup_by_scancode(rc_map, protocol, scancode);
+ if (index < rc_map->len)
+ keycode = rc_map->scan[index].keycode;
+
+ spin_unlock_irqrestore(&rc_map->lock, flags);
+
+ if (keycode != KEY_RESERVED)
+ IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
+ kt->dev->input_name, protocol,
+ (unsigned long long)scancode, keycode);
+
+ return keycode;
+}
+
+
/**
* rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
* @dev: the struct rc_dev descriptor of the device
@@ -576,30 +605,24 @@ out:
* @return: the corresponding keycode, or KEY_RESERVED
*
* This routine is used by drivers which need to convert a scancode to a
- * keycode. Normally it should not be used since drivers should have no
- * interest in keycodes.
+ * keycode. It should not be used since drivers should have no
+ * interest in keycodes. (deprecated)
*/
u32 rc_g_keycode_from_table(struct rc_dev *dev,
enum rc_type protocol, u64 scancode)
{
- struct rc_map *rc_map = &dev->kt->rc_map;
- unsigned int keycode;
- unsigned int index;
- unsigned long flags;
-
- spin_lock_irqsave(&rc_map->lock, flags);
-
- index = ir_lookup_by_scancode(&dev->kt->rc_map, protocol, scancode);
- keycode = index < rc_map->len ?
- rc_map->scan[index].keycode : KEY_RESERVED;
-
- spin_unlock_irqrestore(&rc_map->lock, flags);
+ struct rc_keytable *kt;
+ unsigned int keycode = KEY_RESERVED;
- if (keycode != KEY_RESERVED)
- IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
- dev->input_name, protocol,
- (unsigned long long)scancode, keycode);
+ /* FIXME: This entire function is a hack. Remove it */
+ rcu_read_lock();
+ kt = rcu_dereference(dev->keytables[0]);
+ if (!kt)
+ goto out;
+ keycode = rc_get_keycode(kt, protocol, scancode);
+out:
+ rcu_read_unlock();
return keycode;
}
EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
@@ -715,7 +738,7 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
spin_lock_irqsave(&kt->keylock, flags);
- keycode = rc_g_keycode_from_table(kt->dev, protocol, scancode);
+ keycode = rc_get_keycode(kt, protocol, scancode);
new_event = !kt->keypressed || kt->last_protocol != protocol ||
kt->last_scancode != scancode || kt->last_toggle != toggle;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 620cd8d..47e778b 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -110,7 +110,12 @@ EXPORT_SYMBOL_GPL(rc_event);
*/
void rc_keyup(struct rc_dev *dev)
{
- rc_keytable_keyup(dev->kt);
+ struct rc_keytable *kt;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(kt, &dev->keytable_list, node)
+ rc_keytable_keyup(kt);
+ rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(rc_keyup);
@@ -124,7 +129,13 @@ EXPORT_SYMBOL_GPL(rc_keyup);
*/
void rc_repeat(struct rc_dev *dev)
{
- rc_keytable_repeat(dev->kt);
+ struct rc_keytable *kt;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(kt, &dev->keytable_list, node)
+ rc_keytable_repeat(kt);
+ rcu_read_unlock();
+
rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
}
EXPORT_SYMBOL_GPL(rc_repeat);
@@ -144,7 +155,13 @@ EXPORT_SYMBOL_GPL(rc_repeat);
void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol,
u64 scancode, u8 toggle, bool autoup)
{
- rc_keytable_keydown(dev->kt, protocol, scancode, toggle, autoup);
+ struct rc_keytable *kt;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(kt, &dev->keytable_list, node)
+ rc_keytable_keydown(kt, protocol, scancode, toggle, autoup);
+ rcu_read_unlock();
+
rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
@@ -447,6 +464,7 @@ struct rc_dev *rc_allocate_device(void)
INIT_LIST_HEAD(&dev->client_list);
spin_lock_init(&dev->client_lock);
+ INIT_LIST_HEAD(&dev->keytable_list);
INIT_KFIFO(dev->txfifo);
spin_lock_init(&dev->txlock);
init_waitqueue_head(&dev->rxwait);
@@ -478,6 +496,43 @@ void rc_free_device(struct rc_dev *dev)
}
EXPORT_SYMBOL_GPL(rc_free_device);
+static int rc_add_keytable(struct rc_dev *dev, const char *map_name)
+{
+ struct rc_keytable *kt;
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
+ if (!dev->keytables[i])
+ break;
+
+ if (i >= ARRAY_SIZE(dev->keytables))
+ return -ENFILE;
+
+ kt = rc_keytable_create(dev, map_name);
+ if (!kt)
+ return -ENOMEM;
+
+ rcu_assign_pointer(dev->keytables[i], kt);
+ list_add_rcu(&kt->node, &dev->keytable_list);
+ synchronize_rcu();
+ return 0;
+}
+
+static void rc_remove_keytable(struct rc_dev *dev, unsigned i)
+{
+ struct rc_keytable *kt;
+
+ if (i >= ARRAY_SIZE(dev->keytables))
+ return;
+
+ kt = dev->keytables[i];
+ rcu_assign_pointer(dev->keytables[i], NULL);
+ if (kt)
+ list_del_rcu(&kt->node);
+ synchronize_rcu();
+ rc_keytable_destroy(kt);
+}
+
int rc_register_device(struct rc_dev *dev)
{
static bool raw_init = false; /* raw decoders loaded? */
@@ -538,11 +593,9 @@ int rc_register_device(struct rc_dev *dev)
if (rc)
goto out_chardev;
- dev->kt = rc_keytable_create(dev, dev->map_name);
- if (!dev->kt) {
- rc = -ENOMEM;
+ rc = rc_add_keytable(dev, dev->map_name);
+ if (rc < 0)
goto out_device;
- }
mutex_unlock(&rc_dev_table_mutex);
@@ -573,12 +626,15 @@ EXPORT_SYMBOL_GPL(rc_register_device);
void rc_unregister_device(struct rc_dev *dev)
{
struct rc_client *client;
+ unsigned i;
if (!dev)
return;
mutex_lock(&dev->lock);
dev->exist = false;
+ for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
+ rc_remove_keytable(dev, i);
mutex_unlock(&dev->lock);
mutex_lock(&rc_dev_table_mutex);
@@ -595,7 +651,6 @@ void rc_unregister_device(struct rc_dev *dev)
if (dev->driver_type == RC_DRIVER_IR_RAW)
ir_raw_event_unregister(dev);
- rc_keytable_destroy(dev->kt);
device_unregister(&dev->dev);
}
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index e34815b..0844e17 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -254,6 +254,7 @@ struct ir_raw_event {
* @get_ir_tx: allow driver to provide tx settings
* @set_ir_tx: allow driver to change tx settings
*/
+#define RC_MAX_KEYTABLES 1
struct rc_dev {
struct device dev;
const char *input_name;
@@ -261,7 +262,8 @@ struct rc_dev {
struct input_id input_id;
char *driver_name;
const char *map_name;
- struct rc_keytable *kt;
+ struct rc_keytable *keytables[RC_MAX_KEYTABLES];
+ struct list_head keytable_list;
struct mutex lock;
unsigned int minor;
bool exist;
@@ -303,6 +305,7 @@ struct rc_dev {
/**
* struct rc_keytable - represents one keytable for a rc_dev device
+ * @node: used to iterate over all keytables for a rc_dev device
* @dev: the rc_dev device this keytable belongs to
* @idev: the input_dev device which belongs to this keytable
* @rc_map: holds the scancode <-> keycode mappings
@@ -316,6 +319,7 @@ struct rc_dev {
* @last_toggle: toggle of the last keypress
*/
struct rc_keytable {
+ struct list_head node;
struct rc_dev *dev;
struct input_dev *idev;
struct rc_map rc_map;
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 28/43] rc-core: add ioctls for adding/removing keytables from userspace
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (26 preceding siblings ...)
2012-05-23 9:44 ` [PATCH 27/43] rc-core: make the keytable of rc_dev an array David Härdeman
@ 2012-05-23 9:44 ` David Härdeman
2012-05-23 9:44 ` [PATCH 29/43] rc-core: remove redundant spinlock David Härdeman
` (15 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:44 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
As all the basics are now in place, we can finally add the ioctls
for adding/removing keytables from userspace.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-core-priv.h | 3 +
drivers/media/rc/rc-keytable.c | 6 ++-
drivers/media/rc/rc-main.c | 82 +++++++++++++++++++++++++++++++++++----
include/media/rc-core.h | 27 ++++++++++++-
4 files changed, 107 insertions(+), 11 deletions(-)
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 7aaa1bf..8006c2e 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -156,7 +156,8 @@ void rc_keytable_keyup(struct rc_keytable *kt);
void rc_keytable_repeat(struct rc_keytable *kt);
void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
u64 scancode, u8 toggle, bool autokeyup);
-struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *map_name);
+struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name,
+ const char *map_name);
void rc_keytable_destroy(struct rc_keytable *kt);
/* Only to be used by rc-core and ir-lirc-codec */
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index f422a3b..bdb60f4 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -818,6 +818,7 @@ static void rc_input_close(struct input_dev *idev)
/**
* rc_keytable_create() - creates a new keytable
* @dev: the struct rc_dev device this keytable should belong to
+ * @name: the userfriendly name of this keymap
* @map_name: the name of the keymap to autoload
* @return: a new struct rc_keytable pointer or NULL on error
*
@@ -825,7 +826,9 @@ static void rc_input_close(struct input_dev *idev)
* keytable and an input device along with some state (whether a key
* is currently pressed or not, etc).
*/
-struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *map_name)
+struct rc_keytable *rc_keytable_create(struct rc_dev *dev,
+ const char *name,
+ const char *map_name)
{
struct rc_keytable *kt;
struct input_dev *idev = NULL;
@@ -842,6 +845,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *map_name)
kt->idev = idev;
kt->dev = dev;
+ snprintf(kt->name, sizeof(*kt->name), name ? name : "undefined");
idev->getkeycode = ir_getkeycode;
idev->setkeycode = ir_setkeycode;
idev->open = rc_input_open;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 47e778b..a9c7226 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -496,7 +496,8 @@ void rc_free_device(struct rc_dev *dev)
}
EXPORT_SYMBOL_GPL(rc_free_device);
-static int rc_add_keytable(struct rc_dev *dev, const char *map_name)
+static int rc_add_keytable(struct rc_dev *dev, const char *name,
+ const char *map_name)
{
struct rc_keytable *kt;
unsigned i;
@@ -508,7 +509,7 @@ static int rc_add_keytable(struct rc_dev *dev, const char *map_name)
if (i >= ARRAY_SIZE(dev->keytables))
return -ENFILE;
- kt = rc_keytable_create(dev, map_name);
+ kt = rc_keytable_create(dev, name, map_name);
if (!kt)
return -ENOMEM;
@@ -518,19 +519,21 @@ static int rc_add_keytable(struct rc_dev *dev, const char *map_name)
return 0;
}
-static void rc_remove_keytable(struct rc_dev *dev, unsigned i)
+static int rc_remove_keytable(struct rc_dev *dev, unsigned i)
{
struct rc_keytable *kt;
- if (i >= ARRAY_SIZE(dev->keytables))
- return;
-
kt = dev->keytables[i];
rcu_assign_pointer(dev->keytables[i], NULL);
if (kt)
list_del_rcu(&kt->node);
synchronize_rcu();
+
+ if (!kt)
+ return -EINVAL;
+
rc_keytable_destroy(kt);
+ return 0;
}
int rc_register_device(struct rc_dev *dev)
@@ -593,7 +596,7 @@ int rc_register_device(struct rc_dev *dev)
if (rc)
goto out_chardev;
- rc = rc_add_keytable(dev, dev->map_name);
+ rc = rc_add_keytable(dev, dev->map_name, dev->map_name);
if (rc < 0)
goto out_device;
@@ -938,6 +941,8 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
unsigned int __user *ip = (unsigned int __user *)p;
struct rc_ir_rx rx;
struct rc_ir_tx tx;
+ struct rc_keytable_ioctl ktio;
+ struct rc_keytable *kt;
int error;
switch (cmd) {
@@ -999,8 +1004,69 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
return -EFAULT;
return 0;
- }
+ case RCIOCADDTABLE:
+ if (copy_from_user(&ktio, p, sizeof(ktio)))
+ return -EFAULT;
+
+ if (ktio.id >= RC_MAX_KEYTABLES)
+ return -EINVAL;
+
+ if (ktio.flags)
+ return -EINVAL;
+
+ ktio.name[sizeof(ktio.name) - 1] = '\0';
+ if (strlen(ktio.name) < 1)
+ return -EINVAL;
+
+ error = rc_add_keytable(dev, ktio.name, NULL);
+ if (error < 0)
+ return error;
+ ktio.id = error;
+
+ if (copy_to_user(p, &ktio, sizeof(ktio)))
+ return -EFAULT;
+
+ return 0;
+
+ case RCIOCGTABLENAME:
+ if (copy_from_user(&ktio, p, sizeof(ktio)))
+ return -EFAULT;
+
+ if (ktio.id >= RC_MAX_KEYTABLES)
+ return -EINVAL;
+
+ if (ktio.flags)
+ return -EINVAL;
+
+ rcu_read_lock();
+ kt = rcu_dereference(dev->keytables[ktio.id]);
+ if (kt) {
+ ktio.name[0] = '\0';
+ strncat(ktio.name, kt->name, sizeof(ktio.name));
+ }
+ rcu_read_unlock();
+
+ if (!kt)
+ return -EINVAL;
+
+ if (copy_to_user(p, &ktio, sizeof(ktio)))
+ return -EFAULT;
+
+ return 0;
+
+ case RCIOCDELTABLE:
+ if (copy_from_user(&ktio, p, sizeof(ktio)))
+ return -EFAULT;
+
+ if (ktio.id >= RC_MAX_KEYTABLES)
+ return -EINVAL;
+
+ if (ktio.flags)
+ return -EINVAL;
+
+ return rc_remove_keytable(dev, ktio.id);
+ }
return -EINVAL;
}
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 0844e17..1852b47 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -152,6 +152,29 @@ struct rc_ir_tx {
__u32 reserved[9];
} __packed;
+/* add a keytable */
+#define RCIOCADDTABLE _IOC(_IOC_READ | _IOC_WRITE, RC_IOC_MAGIC, 0x06, sizeof(struct rc_keytable_ioctl))
+
+/* get the name of a keytable */
+#define RCIOCGTABLENAME _IOC(_IOC_READ, RC_IOC_MAGIC, 0x06, sizeof(struct rc_keytable_ioctl))
+
+/* remove a keytable */
+#define RCIOCDELTABLE _IOC(_IOC_WRITE, RC_IOC_MAGIC, 0x06, sizeof(struct rc_keytable_ioctl))
+
+/**
+ * struct rc_keytable_ioctl - used to alter keytables
+ * @id: the id of the keytable
+ * @flags: flags for the keytable
+ * @reserved: for future use, set to zero
+ * @name: a user-friendly name for the keytable
+ */
+#define RC_KEYTABLE_NAME_SIZE 128
+struct rc_keytable_ioctl {
+ __u32 id;
+ __u32 flags;
+ __u32 reserved[4];
+ char name[RC_KEYTABLE_NAME_SIZE];
+} __packed;
enum rc_driver_type {
RC_DRIVER_SCANCODE = 0, /* Driver or hardware generates a scancode */
@@ -254,7 +277,7 @@ struct ir_raw_event {
* @get_ir_tx: allow driver to provide tx settings
* @set_ir_tx: allow driver to change tx settings
*/
-#define RC_MAX_KEYTABLES 1
+#define RC_MAX_KEYTABLES 32
struct rc_dev {
struct device dev;
const char *input_name;
@@ -308,6 +331,7 @@ struct rc_dev {
* @node: used to iterate over all keytables for a rc_dev device
* @dev: the rc_dev device this keytable belongs to
* @idev: the input_dev device which belongs to this keytable
+ * @name: the user-friendly name of this keytable
* @rc_map: holds the scancode <-> keycode mappings
* @keypressed: whether a key is currently pressed or not
* @keyup_jiffies: when the key should be auto-released
@@ -322,6 +346,7 @@ struct rc_keytable {
struct list_head node;
struct rc_dev *dev;
struct input_dev *idev;
+ char name[RC_KEYTABLE_NAME_SIZE];
struct rc_map rc_map;
bool keypressed;
unsigned long keyup_jiffies;
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 29/43] rc-core: remove redundant spinlock
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (27 preceding siblings ...)
2012-05-23 9:44 ` [PATCH 28/43] rc-core: add ioctls for adding/removing keytables from userspace David Härdeman
@ 2012-05-23 9:44 ` David Härdeman
2012-05-23 9:44 ` [PATCH 30/43] rc-core: make keytable RCU-friendly David Härdeman
` (14 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:44 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Remove a redundant spinlock from struct rc_map.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-keytable.c | 43 +++++++++++++++++-----------------------
include/media/rc-core.h | 4 ++--
include/media/rc-map.h | 1 -
3 files changed, 20 insertions(+), 28 deletions(-)
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index bdb60f4..eb48358 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -335,7 +335,7 @@ static int ir_setkeycode(struct input_dev *idev,
entry.keycode = ke->keycode;
- spin_lock_irqsave(&rc_map->lock, flags);
+ spin_lock_irqsave(&kt->lock, flags);
if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
index = ke->index;
@@ -391,7 +391,7 @@ static int ir_setkeycode(struct input_dev *idev,
*old_keycode = ir_update_mapping(kt, rc_map, index, ke->keycode);
out:
- spin_unlock_irqrestore(&rc_map->lock, flags);
+ spin_unlock_irqrestore(&kt->lock, flags);
return retval;
}
@@ -495,7 +495,7 @@ static int ir_getkeycode(struct input_dev *idev,
unsigned int index;
int retval;
- spin_lock_irqsave(&rc_map->lock, flags);
+ spin_lock_irqsave(&kt->lock, flags);
if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
index = ke->index;
@@ -564,7 +564,7 @@ static int ir_getkeycode(struct input_dev *idev,
retval = 0;
out:
- spin_unlock_irqrestore(&rc_map->lock, flags);
+ spin_unlock_irqrestore(&kt->lock, flags);
return retval;
}
@@ -574,25 +574,15 @@ static u32 rc_get_keycode(struct rc_keytable *kt,
struct rc_map *rc_map;
unsigned int keycode = KEY_RESERVED;
unsigned int index;
- unsigned long flags;
rc_map = &kt->rc_map;
if (!rc_map)
return KEY_RESERVED;
- spin_lock_irqsave(&rc_map->lock, flags);
-
index = ir_lookup_by_scancode(rc_map, protocol, scancode);
if (index < rc_map->len)
keycode = rc_map->scan[index].keycode;
- spin_unlock_irqrestore(&rc_map->lock, flags);
-
- if (keycode != KEY_RESERVED)
- IR_dprintk(1, "%s: protocol 0x%04x scancode 0x%08llx keycode 0x%02x\n",
- kt->dev->input_name, protocol,
- (unsigned long long)scancode, keycode);
-
return keycode;
}
@@ -613,13 +603,17 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev,
{
struct rc_keytable *kt;
unsigned int keycode = KEY_RESERVED;
+ unsigned long flags;
/* FIXME: This entire function is a hack. Remove it */
rcu_read_lock();
kt = rcu_dereference(dev->keytables[0]);
if (!kt)
goto out;
+
+ spin_lock_irqsave(&kt->lock, flags);
keycode = rc_get_keycode(kt, protocol, scancode);
+ spin_unlock_irqrestore(&kt->lock, flags);
out:
rcu_read_unlock();
@@ -633,7 +627,7 @@ EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
* @sync: whether or not to call input_sync
*
* This function is used internally to release a keypress, it must be
- * called with keylock held.
+ * called with kt->lock held.
*/
static void rc_do_keyup(struct rc_keytable *kt, bool sync)
{
@@ -658,9 +652,9 @@ void rc_keytable_keyup(struct rc_keytable *kt)
{
unsigned long flags;
- spin_lock_irqsave(&kt->keylock, flags);
+ spin_lock_irqsave(&kt->lock, flags);
rc_do_keyup(kt, true);
- spin_unlock_irqrestore(&kt->keylock, flags);
+ spin_unlock_irqrestore(&kt->lock, flags);
}
/**
@@ -685,10 +679,10 @@ static void rc_timer_keyup(unsigned long cookie)
* to allow the input subsystem to do its auto-repeat magic or
* a keyup event might follow immediately after the keydown.
*/
- spin_lock_irqsave(&kt->keylock, flags);
+ spin_lock_irqsave(&kt->lock, flags);
if (time_is_before_eq_jiffies(kt->keyup_jiffies))
rc_do_keyup(kt, true);
- spin_unlock_irqrestore(&kt->keylock, flags);
+ spin_unlock_irqrestore(&kt->lock, flags);
}
/**
@@ -703,7 +697,7 @@ void rc_keytable_repeat(struct rc_keytable *kt)
{
unsigned long flags;
- spin_lock_irqsave(&kt->keylock, flags);
+ spin_lock_irqsave(&kt->lock, flags);
input_event(kt->idev, EV_MSC, MSC_SCAN, kt->last_scancode);
input_sync(kt->idev);
@@ -715,7 +709,7 @@ void rc_keytable_repeat(struct rc_keytable *kt)
mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
out:
- spin_unlock_irqrestore(&kt->keylock, flags);
+ spin_unlock_irqrestore(&kt->lock, flags);
}
/**
@@ -736,7 +730,7 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
u32 keycode;
bool new_event;
- spin_lock_irqsave(&kt->keylock, flags);
+ spin_lock_irqsave(&kt->lock, flags);
keycode = rc_get_keycode(kt, protocol, scancode);
new_event = !kt->keypressed || kt->last_protocol != protocol ||
@@ -767,7 +761,7 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
kt->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
}
- spin_unlock_irqrestore(&kt->keylock, flags);
+ spin_unlock_irqrestore(&kt->lock, flags);
}
/**
@@ -891,8 +885,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev,
*/
idev->rep[REP_PERIOD] = 125;
- spin_lock_init(&kt->rc_map.lock);
- spin_lock_init(&kt->keylock);
+ spin_lock_init(&kt->lock);
return kt;
out:
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 1852b47..cd93623 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -336,7 +336,7 @@ struct rc_dev {
* @keypressed: whether a key is currently pressed or not
* @keyup_jiffies: when the key should be auto-released
* @timer_keyup: responsible for the auto-release of keys
- * @keylock: protects the key state
+ * @lock: protects the key state
* @last_keycode: keycode of the last keypress
* @last_protocol: protocol of the last keypress
* @last_scancode: scancode of the last keypress
@@ -351,7 +351,7 @@ struct rc_keytable {
bool keypressed;
unsigned long keyup_jiffies;
struct timer_list timer_keyup;
- spinlock_t keylock;
+ spinlock_t lock;
u32 last_keycode;
enum rc_type last_protocol;
u64 last_scancode;
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 7de8215..5737c65 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -90,7 +90,6 @@ struct rc_map {
unsigned int alloc; /* Size of *scan in bytes */
enum rc_type rc_type; /* For in-kernel keymaps */
const char *name;
- spinlock_t lock;
};
struct rc_map_list {
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 30/43] rc-core: make keytable RCU-friendly
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (28 preceding siblings ...)
2012-05-23 9:44 ` [PATCH 29/43] rc-core: remove redundant spinlock David Härdeman
@ 2012-05-23 9:44 ` David Härdeman
2012-05-23 9:44 ` [PATCH 31/43] rc-core: allow empty keymaps David Härdeman
` (13 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:44 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Change struct rc_keytable to be RCU-friendly by kmalloc():ing an
entire new scancode,protocol <-> keycode table every time the table
is changed (i.e. via EVIOCSKEYCODE(_V2)).
The advantage is that the performance-critical keycode lookup path
can be made entirely lock-free and that GFP_ATOMIC allocations
can be avoided entirely at the cost of a couple of extra kmalloc()
calls when changing a keytable (which is normally done once during
boot).
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-keytable.c | 671 +++++++++++++++++++---------------------
include/media/rc-core.h | 32 +-
2 files changed, 334 insertions(+), 369 deletions(-)
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index eb48358..d6e68d0 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -24,12 +24,10 @@
#include <linux/poll.h>
#include "rc-core-priv.h"
-/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
-#define RC_TAB_MIN_SIZE 256
-#define RC_TAB_MAX_SIZE 8192
+#define RC_TAB_MAX_SIZE 1024 /* entries */
-/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
-#define IR_KEYPRESS_TIMEOUT 250
+/* FIXME: RC_KEYPRESS_TIMEOUT should be protocol specific */
+#define RC_KEYPRESS_TIMEOUT 250
/* Used to keep track of known keymaps */
static LIST_HEAD(rc_map_list);
@@ -98,248 +96,238 @@ void rc_map_unregister(struct rc_map_list *map)
EXPORT_SYMBOL_GPL(rc_map_unregister);
/**
- * ir_create_table() - initializes a scancode table
- * @rc_map: the rc_map to initialize
- * @name: name to assign to the table
- * @size: initial size of the table
- * @return: zero on success or a negative error code
- *
- * This routine will initialize the rc_map and will allocate
- * memory to hold at least the specified number of elements.
+ * rc_scan_size() - determine the necessary size for a rc_scan struct
+ * @len: the number of keytable entries the struct should hold
+ * @return: the size of the struct in bytes
*/
-static int ir_create_table(struct rc_map *rc_map,
- const char *name, size_t size)
+static inline size_t rc_scan_size(unsigned len)
{
- rc_map->name = name;
- rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
- rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
- rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
- if (!rc_map->scan)
- return -ENOMEM;
-
- IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
- rc_map->size, rc_map->alloc);
- return 0;
+ return sizeof(struct rc_scan) + len * sizeof(struct rc_map_table);
}
/**
- * ir_free_table() - frees memory allocated by a scancode table
- * @rc_map: the table whose mappings need to be freed
+ * rc_keytable_update_entry() - update an existing entry in the keytable
+ * @kt: the keytable to update
+ * @i: the index of the entry to update
+ * @entry: the new values for the entry
+ * @return: the old rc_scan struct, NULL if memory could not be allocated
*
- * This routine will free memory alloctaed for key mappings used by given
- * scancode table.
+ * Updates a keytable by replacing an existing entry at the given index.
+ * The old rc_scan struct is returned so that it can be freed at a
+ * later stage.
*/
-static void ir_free_table(struct rc_map *rc_map)
+static struct rc_scan *rc_keytable_update_entry(struct rc_keytable *kt,
+ unsigned i,
+ struct rc_map_table *entry)
{
- rc_map->size = 0;
- kfree(rc_map->scan);
- rc_map->scan = NULL;
-}
+ struct rc_scan *old_scan = kt->scan;
+ struct rc_scan *new_scan = kt->scan;
+ u32 old_keycode;
-/**
- * ir_resize_table() - resizes a scancode table if necessary
- * @rc_map: the rc_map to resize
- * @gfp_flags: gfp flags to use when allocating memory
- * @return: zero on success or a negative error code
- *
- * This routine will shrink the rc_map if it has lots of
- * unused entries and grow it if it is full.
- */
-static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
-{
- unsigned int oldalloc = rc_map->alloc;
- unsigned int newalloc = oldalloc;
- struct rc_map_table *oldscan = rc_map->scan;
- struct rc_map_table *newscan;
-
- if (rc_map->size == rc_map->len) {
- /* All entries in use -> grow keytable */
- if (rc_map->alloc >= RC_TAB_MAX_SIZE)
- return -ENOMEM;
-
- newalloc *= 2;
- IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
- }
+ if (i >= old_scan->len)
+ return NULL;
- if ((rc_map->len * 3 < rc_map->size) && (oldalloc > RC_TAB_MIN_SIZE)) {
- /* Less than 1/3 of entries in use -> shrink keytable */
- newalloc /= 2;
- IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
- }
+ new_scan = kmalloc(rc_scan_size(old_scan->len), GFP_KERNEL);
+ if (!new_scan)
+ return NULL;
+ memcpy(new_scan, old_scan, rc_scan_size(old_scan->len));
- if (newalloc == oldalloc)
- return 0;
+ IR_dprintk(1, "#%d: New keycode 0x%04x\n", i, entry->keycode);
+ new_scan->table[i].keycode = entry->keycode;
- newscan = kmalloc(newalloc, gfp_flags);
- if (!newscan) {
- IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
- return -ENOMEM;
- }
+ /* Another scancode might use the old keycode... */
+ __set_bit(entry->keycode, kt->idev->keybit);
+ old_keycode = old_scan->table[i].keycode;
+ for (i = 0; i < new_scan->len; i++)
+ if (new_scan->table[i].keycode == old_keycode)
+ break;
- memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table));
- rc_map->scan = newscan;
- rc_map->alloc = newalloc;
- rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
- kfree(oldscan);
- return 0;
+ if (i >= new_scan->len)
+ /* ...nope */
+ __clear_bit(old_keycode, kt->idev->keybit);
+
+ rcu_assign_pointer(kt->scan, new_scan);
+ return old_scan;
}
/**
- * ir_update_mapping() - set a keycode in the scancode->keycode table
- * @kt: the struct rc_keytable descriptor
- * @rc_map: scancode table to be adjusted
- * @index: index of the mapping that needs to be updated
- * @keycode: the desired keycode
- * @return: previous keycode assigned to the mapping
+ * rc_keytable_remove_entry() - remove an existing entry in the keytable
+ * @kt: the keytable to update
+ * @i: the index of the entry to remove
+ * @return: the old rc_scan struct, NULL if memory could not be allocated
*
- * This routine is used to update scancode->keycode mapping at given
- * position.
+ * Updates a keytable by removing an existing entry at the given index.
+ * The old rc_scan struct is returned so that it can be freed at a
+ * later stage.
*/
-static unsigned int ir_update_mapping(struct rc_keytable *kt,
- struct rc_map *rc_map,
- unsigned int index,
- unsigned int new_keycode)
+static struct rc_scan *rc_keytable_remove_entry(struct rc_keytable *kt,
+ unsigned i)
{
- int old_keycode = rc_map->scan[index].keycode;
- int i;
-
- /* Did the user wish to remove the mapping? */
- if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
- IR_dprintk(1, "#%d: Deleting proto 0x%04x, scan 0x%08llx\n",
- index, rc_map->scan[index].protocol,
- (unsigned long long)rc_map->scan[index].scancode);
- rc_map->len--;
- memmove(&rc_map->scan[index], &rc_map->scan[index + 1],
- (rc_map->len - index) * sizeof(struct rc_map_table));
- } else {
- IR_dprintk(1, "#%d: %s proto 0x%04x, scan 0x%08llx "
- "with key 0x%04x\n",
- index,
- old_keycode == KEY_RESERVED ? "New" : "Replacing",
- rc_map->scan[index].protocol,
- (unsigned long long)rc_map->scan[index].scancode,
- new_keycode);
- rc_map->scan[index].keycode = new_keycode;
- __set_bit(new_keycode, kt->idev->keybit);
- }
+ struct rc_scan *old_scan = kt->scan;
+ struct rc_scan *new_scan = kt->scan;
+ u32 old_keycode;
- if (old_keycode != KEY_RESERVED) {
- /* A previous mapping was updated... */
- __clear_bit(old_keycode, kt->idev->keybit);
- /* ... but another scancode might use the same keycode */
- for (i = 0; i < rc_map->len; i++) {
- if (rc_map->scan[i].keycode == old_keycode) {
- __set_bit(old_keycode, kt->idev->keybit);
- break;
- }
- }
+ if (i >= old_scan->len)
+ return NULL;
- /* Possibly shrink the keytable, failure is not a problem */
- ir_resize_table(rc_map, GFP_ATOMIC);
- }
+ new_scan = kmalloc(rc_scan_size(old_scan->len - 1), GFP_ATOMIC);
+ if (!new_scan)
+ return NULL;
+ new_scan->len = old_scan->len - 1;
+ memcpy(&new_scan->table[0], &old_scan->table[0],
+ i * sizeof(struct rc_map_table));
+ memcpy(&new_scan->table[i], &old_scan->table[i + 1],
+ (new_scan->len - i) * sizeof(struct rc_map_table));
+ IR_dprintk(1, "#%d: Deleted\n", i);
+
+ /* Another scancode might use the removed keycode... */
+ old_keycode = old_scan->table[i].keycode;
+ for (i = 0; i < new_scan->len; i++)
+ if (new_scan->table[i].keycode == old_keycode)
+ break;
+
+ if (i >= new_scan->len)
+ /* ...nope */
+ __clear_bit(old_keycode, kt->idev->keybit);
- return old_keycode;
+ rcu_assign_pointer(kt->scan, new_scan);
+ return old_scan;
}
/**
- * ir_establish_scancode() - set a keycode in the scancode->keycode table
- * @kt: the struct rc_keytable descriptor
- * @rc_map: scancode table to be searched
- * @entry: the entry to be added to the table
- * @resize: controls whether we are allowed to resize the table to
- * accomodate not yet present scancodes
- * @return: index of the mapping containing scancode in question
- * or -1U in case of failure.
+ * rc_keytable_add_entry() - add an existing entry in the keytable
+ * @kt: the keytable to update
+ * @entry: the new entry to insert
+ * @init: whether the keytable is being initialized for the first time
+ * @return: the old rc_scan struct, NULL if memory could not be allocated
*
- * This routine is used to locate given scancode in rc_map.
- * If scancode is not yet present the routine will allocate a new slot
- * for it.
+ * Updates a keytable by inserting an entry at the proper index. Unless @init is
+ * %true, the old rc_scan struct is returned so that it can be freed at a
+ * later stage.
*/
-static unsigned int ir_establish_scancode(struct rc_keytable *kt,
- struct rc_map *rc_map,
- struct rc_map_table *entry,
- bool resize)
+static struct rc_scan *rc_keytable_add_entry(struct rc_keytable *kt,
+ struct rc_map_table *entry,
+ bool init)
{
- unsigned int i;
+ struct rc_scan *old_scan = kt->scan;
+ struct rc_scan *new_scan = kt->scan;
+ unsigned i;
- /*
- * Unfortunately, some hardware-based IR decoders don't provide
- * all bits for the complete IR code. In general, they provide only
- * the command part of the IR code. Yet, as it is possible to replace
- * the provided IR with another one, it is needed to allow loading
- * IR tables from other remotes. So, we support specifying a mask to
- * indicate the valid bits of the scancodes.
- */
- if (kt->dev->scanmask)
- entry->scancode &= kt->dev->scanmask;
+ if (old_scan->len >= RC_TAB_MAX_SIZE)
+ return NULL;
- /*
- * First check if we already have a mapping for this command.
- * Note that the keytable is sorted first on protocol and second
- * on scancode (lowest to highest).
- */
- for (i = 0; i < rc_map->len; i++) {
- if (rc_map->scan[i].protocol < entry->protocol)
+ /* Find the right index to insert the new entry at */
+ for (i = 0; i < old_scan->len; i++) {
+ if (old_scan->table[i].protocol < entry->protocol)
continue;
- if (rc_map->scan[i].protocol > entry->protocol)
+ if (old_scan->table[i].protocol > entry->protocol)
break;
- if (rc_map->scan[i].scancode < entry->scancode)
+ if (old_scan->table[i].scancode < entry->scancode)
continue;
- if (rc_map->scan[i].scancode > entry->scancode)
+ if (old_scan->table[i].scancode > entry->scancode)
break;
- return i;
+ /* BUG: We already have a matching entry */
+ return NULL;
}
- /* No previous mapping found, we might need to grow the table */
- if (rc_map->size == rc_map->len) {
- if (!resize || ir_resize_table(rc_map, GFP_ATOMIC))
- return -1U;
+ if (init) {
+ /* The init code already allocates a suitably sized table */
+ memmove(&new_scan->table[i + 1], &new_scan->table[i],
+ (new_scan->len - i) * sizeof(struct rc_map_table));
+ new_scan->len++;
+ } else {
+ new_scan = kmalloc(rc_scan_size(old_scan->len + 1), GFP_ATOMIC);
+ if (!new_scan)
+ return NULL;
+ new_scan->len = old_scan->len + 1;
+ memcpy(&new_scan->table[0], &old_scan->table[0],
+ i * sizeof(struct rc_map_table));
+ memcpy(&new_scan->table[i + 1], &old_scan->table[i],
+ (old_scan->len - i) * sizeof(struct rc_map_table));
}
- /* i is the proper index to insert our new keycode */
- if (i < rc_map->len)
- memmove(&rc_map->scan[i + 1], &rc_map->scan[i],
- (rc_map->len - i) * sizeof(struct rc_map_table));
- rc_map->scan[i].scancode = entry->scancode;
- rc_map->scan[i].protocol = entry->protocol;
- rc_map->scan[i].keycode = KEY_RESERVED;
- rc_map->len++;
+ new_scan->table[i].scancode = entry->scancode;
+ new_scan->table[i].protocol = entry->protocol;
+ new_scan->table[i].keycode = entry->keycode;
+ IR_dprintk(1, "#%d: New proto 0x%04x, scan 0x%08llx with key 0x%04x\n",
+ i, entry->protocol, (unsigned long long)entry->scancode,
+ entry->keycode);
+ __set_bit(entry->keycode, kt->idev->keybit);
- return i;
+ rcu_assign_pointer(kt->scan, new_scan);
+ return old_scan;
}
/**
- * ir_setkeycode() - set a keycode in the scancode->keycode table
+ * rc_scancode_to_index() - locate keytable index by scancode
+ * @rc_scan: the struct rc_scan to search
+ * @protocol: protocol to look for in the table
+ * @scancode: scancode to look for in the table
+ * @return: index in the table, -1U if not found
+ *
+ * This routine performs a binary search in a keytable for a
+ * given scancode.
+ */
+static unsigned rc_scancode_to_index(struct rc_scan *scan,
+ u16 protocol, u64 scancode)
+{
+ int start = 0;
+ int end = scan->len - 1;
+ int mid;
+ struct rc_map_table *m;
+
+ while (start <= end) {
+ mid = (start + end) / 2;
+ m = &scan->table[mid];
+
+ if (m->protocol < protocol)
+ start = mid + 1;
+ else if (m->protocol > protocol)
+ end = mid - 1;
+ else if (m->scancode < scancode)
+ start = mid + 1;
+ else if (m->scancode > scancode)
+ end = mid - 1;
+ else
+ return mid;
+ }
+
+ return -1U;
+}
+
+/**
+ * rc_keytable_set() - add/update/remove an entry in the keytable
* @idev: the struct input_dev device descriptor
- * @scancode: the desired scancode
- * @keycode: result
- * @return: -EINVAL if the keycode could not be inserted, otherwise zero.
+ * @ke: the keymap entry to add/update/remove
+ * @old_keycode:used to return the previous keycode for this entry
+ * @return: zero on success or a negative error code
*
- * This routine is used to handle evdev EVIOCSKEY ioctl.
+ * This function handles the evdev EVIOCSKEYCODE(_V2) ioctls.
*/
-static int ir_setkeycode(struct input_dev *idev,
- const struct input_keymap_entry *ke,
- unsigned int *old_keycode)
+static int rc_keytable_set(struct input_dev *idev,
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
{
struct rc_keytable *kt = input_get_drvdata(idev);
struct rc_dev *rdev = kt->dev;
- struct rc_map *rc_map = &kt->rc_map;
+ struct rc_scan *old_scan = NULL;
unsigned int index;
struct rc_map_table entry;
int retval = 0;
- unsigned long flags;
entry.keycode = ke->keycode;
- spin_lock_irqsave(&kt->lock, flags);
+ retval = mutex_lock_interruptible(&kt->scan_mutex);
+ if (retval)
+ return retval;
if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
index = ke->index;
- if (index >= rc_map->len) {
+ if (index >= kt->scan->len) {
retval = -EINVAL;
goto out;
}
@@ -356,16 +344,17 @@ static int ir_setkeycode(struct input_dev *idev,
entry.protocol = rdev->enabled_protocols;
else if (hweight64(rdev->allowed_protos) == 1)
entry.protocol = rdev->allowed_protos;
- else if (rc_map->len > 0)
- entry.protocol = rc_map->scan[0].protocol;
+ else if (kt->scan->len > 0)
+ entry.protocol = kt->scan->table[0].protocol;
else
entry.protocol = RC_TYPE_OTHER;
- index = ir_establish_scancode(kt, rc_map, &entry, true);
- if (index >= rc_map->len) {
- retval = -ENOMEM;
- goto out;
- }
+ if (kt->dev->scanmask)
+ entry.scancode &= kt->dev->scanmask;
+
+ index = rc_scancode_to_index(kt->scan, entry.protocol,
+ entry.scancode);
+
} else if (ke->len == sizeof(struct rc_scancode)) {
/* New EVIOCSKEYCODE_V2 ioctl */
const struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
@@ -377,125 +366,63 @@ static int ir_setkeycode(struct input_dev *idev,
goto out;
}
- index = ir_establish_scancode(kt, rc_map, &entry, true);
- if (index >= rc_map->len) {
- retval = -ENOMEM;
- goto out;
- }
+ if (kt->dev->scanmask)
+ entry.scancode &= kt->dev->scanmask;
+
+ index = rc_scancode_to_index(kt->scan, entry.protocol,
+ entry.scancode);
+
} else {
retval = -EINVAL;
goto out;
}
- if (retval == 0)
- *old_keycode = ir_update_mapping(kt, rc_map, index, ke->keycode);
-
-out:
- spin_unlock_irqrestore(&kt->lock, flags);
- return retval;
-}
-
-/**
- * rc_setkeytable() - sets several entries in the scancode->keycode table
- * @dev: the struct rc_dev device descriptor
- * @to: the struct rc_map to copy entries to
- * @from: the struct rc_map to copy entries from
- * @return: -ENOMEM if all keycodes could not be inserted, otherwise zero.
- *
- * This routine is used to handle table initialization.
- */
-static int rc_setkeytable(struct rc_keytable *kt,
- const struct rc_map *from)
-{
- struct rc_map *rc_map = &kt->rc_map;
- struct rc_map_table entry;
- unsigned int i, index;
- int rc;
-
- rc = ir_create_table(rc_map, from->name, from->size);
- if (rc)
- return rc;
-
- IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
- rc_map->size, rc_map->alloc);
-
- for (i = 0; i < from->size; i++) {
- entry.protocol = from->scan[i].protocol;
- entry.scancode = from->scan[i].scancode;
- index = ir_establish_scancode(kt, rc_map, &entry, false);
- if (index >= rc_map->len) {
- rc = -ENOMEM;
- break;
- }
-
- ir_update_mapping(kt, rc_map, index, from->scan[i].keycode);
- }
-
- if (rc)
- ir_free_table(rc_map);
-
- return rc;
-}
-
-/**
- * ir_lookup_by_scancode() - locate mapping by scancode
- * @rc_map: the struct rc_map to search
- * @protocol: protocol to look for in the table
- * @scancode: scancode to look for in the table
- * @return: index in the table, -1U if not found
- *
- * This routine performs binary search in RC keykeymap table for
- * given scancode.
- */
-static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
- u16 protocol, u64 scancode)
-{
- int start = 0;
- int end = rc_map->len - 1;
- int mid;
- struct rc_map_table *m;
-
- while (start <= end) {
- mid = (start + end) / 2;
- m = &rc_map->scan[mid];
-
- if (m->protocol < protocol)
- start = mid + 1;
- else if (m->protocol > protocol)
- end = mid - 1;
- else if (m->scancode < scancode)
- start = mid + 1;
- else if (m->scancode > scancode)
- end = mid - 1;
+ if (index >= kt->scan->len) {
+ /* Old entry not found */
+ *old_keycode = KEY_RESERVED;
+ if (ke->keycode == KEY_RESERVED)
+ /* removing a non-existing entry eh? */
+ goto out;
+ old_scan = rc_keytable_add_entry(kt, &entry, false);
+ } else {
+ /* Previous entry found */
+ *old_keycode = kt->scan->table[index].keycode;
+ if (ke->keycode == KEY_RESERVED)
+ old_scan = rc_keytable_remove_entry(kt, index);
else
- return mid;
+ old_scan = rc_keytable_update_entry(kt, index, &entry);
}
- return -1U;
+out:
+ mutex_unlock(&kt->scan_mutex);
+ if (old_scan) {
+ synchronize_rcu();
+ kfree(old_scan);
+ }
+ return retval;
}
/**
- * ir_getkeycode() - get a keycode from the scancode->keycode table
+ * rc_keytable_get() - get an entry from the keytable
* @idev: the struct input_dev device descriptor
- * @scancode: the desired scancode
- * @keycode: used to return the keycode, if found, or KEY_RESERVED
- * @return: always returns zero.
+ * @ke: the requested entry which is filled in by this function
+ * @return: zero on success, or a negative error code
*
- * This routine is used to handle evdev EVIOCGKEY ioctl.
+ * This function handles the evdev EVIOCGKEYCODE(_V2) ioctls.
*/
-static int ir_getkeycode(struct input_dev *idev,
- struct input_keymap_entry *ke)
+static int rc_keytable_get(struct input_dev *idev,
+ struct input_keymap_entry *ke)
{
struct rc_keymap_entry *rke = (struct rc_keymap_entry *)ke;
struct rc_keytable *kt = input_get_drvdata(idev);
struct rc_dev *rdev = kt->dev;
- struct rc_map *rc_map = &kt->rc_map;
+ struct rc_scan *scan;
struct rc_map_table *entry;
- unsigned long flags;
unsigned int index;
int retval;
- spin_lock_irqsave(&kt->lock, flags);
+ rcu_read_lock();
+ scan = rcu_dereference(kt->scan);
if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
index = ke->index;
@@ -513,12 +440,12 @@ static int ir_getkeycode(struct input_dev *idev,
protocol = rdev->enabled_protocols;
else if (hweight64(rdev->allowed_protos) == 1)
protocol = rdev->allowed_protos;
- else if (rc_map->len > 0)
- protocol = rc_map->scan[0].protocol;
+ else if (scan->len > 0)
+ protocol = scan->table[0].protocol;
else
protocol = RC_TYPE_OTHER;
- index = ir_lookup_by_scancode(rc_map, protocol, scancode);
+ index = rc_scancode_to_index(scan, protocol, scancode);
} else if (ke->len == sizeof(struct rc_scancode)) {
/* New EVIOCGKEYCODE_V2 ioctl */
@@ -527,16 +454,17 @@ static int ir_getkeycode(struct input_dev *idev,
goto out;
}
- index = ir_lookup_by_scancode(rc_map,
- rke->rc.protocol, rke->rc.scancode);
+ index = rc_scancode_to_index(scan,
+ rke->rc.protocol,
+ rke->rc.scancode);
} else {
retval = -EINVAL;
goto out;
}
- if (index < rc_map->len) {
- entry = &rc_map->scan[index];
+ if (index < scan->len) {
+ entry = &scan->table[index];
ke->index = index;
ke->keycode = entry->keycode;
if (ke->len == sizeof(int)) {
@@ -564,29 +492,10 @@ static int ir_getkeycode(struct input_dev *idev,
retval = 0;
out:
- spin_unlock_irqrestore(&kt->lock, flags);
+ rcu_read_unlock();
return retval;
}
-static u32 rc_get_keycode(struct rc_keytable *kt,
- enum rc_type protocol, u64 scancode)
-{
- struct rc_map *rc_map;
- unsigned int keycode = KEY_RESERVED;
- unsigned int index;
-
- rc_map = &kt->rc_map;
- if (!rc_map)
- return KEY_RESERVED;
-
- index = ir_lookup_by_scancode(rc_map, protocol, scancode);
- if (index < rc_map->len)
- keycode = rc_map->scan[index].keycode;
-
- return keycode;
-}
-
-
/**
* rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
* @dev: the struct rc_dev descriptor of the device
@@ -602,18 +511,20 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev,
enum rc_type protocol, u64 scancode)
{
struct rc_keytable *kt;
- unsigned int keycode = KEY_RESERVED;
- unsigned long flags;
+ struct rc_scan *scan;
+ unsigned keycode = KEY_RESERVED;
+ unsigned index;
/* FIXME: This entire function is a hack. Remove it */
rcu_read_lock();
kt = rcu_dereference(dev->keytables[0]);
if (!kt)
goto out;
+ scan = rcu_dereference(kt->scan);
- spin_lock_irqsave(&kt->lock, flags);
- keycode = rc_get_keycode(kt, protocol, scancode);
- spin_unlock_irqrestore(&kt->lock, flags);
+ index = rc_scancode_to_index(scan, protocol, scancode);
+ if (index < scan->len)
+ keycode = scan->table[index].keycode;
out:
rcu_read_unlock();
@@ -622,28 +533,28 @@ out:
EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
/**
- * ir_do_keyup() - internal function to signal the release of a keypress
- * @dev: the struct rc_dev descriptor of the device
+ * rc_do_keyup() - internal function to release a keypress
+ * @kt: the struct rc_keytable descriptor of the keytable
* @sync: whether or not to call input_sync
*
* This function is used internally to release a keypress, it must be
- * called with kt->lock held.
+ * called with kt->key_lock held.
*/
static void rc_do_keyup(struct rc_keytable *kt, bool sync)
{
- if (!kt->keypressed)
+ if (!kt->key_pressed)
return;
IR_dprintk(1, "keyup key 0x%04x\n", kt->last_keycode);
input_report_key(kt->idev, kt->last_keycode, 0);
if (sync)
input_sync(kt->idev);
- kt->keypressed = false;
+ kt->key_pressed = false;
}
/**
* rc_keyup() - signals the release of a keypress
- * @dev: the struct rc_dev descriptor of the device
+ * @kt: the struct rc_keytable descriptor of the keytable
*
* This routine is used to signal that a key has been released on the
* remote control.
@@ -652,14 +563,14 @@ void rc_keytable_keyup(struct rc_keytable *kt)
{
unsigned long flags;
- spin_lock_irqsave(&kt->lock, flags);
+ spin_lock_irqsave(&kt->key_lock, flags);
rc_do_keyup(kt, true);
- spin_unlock_irqrestore(&kt->lock, flags);
+ spin_unlock_irqrestore(&kt->key_lock, flags);
}
/**
- * rc_keytable_timer_keyup() - generates a keyup event after a timeout
- * @cookie: a pointer to the struct rc_dev for the device
+ * rc_timer_keyup() - generates a keyup event after a timeout
+ * @cookie: a pointer to the struct rc_keytable descriptor of the keytable
*
* This routine will generate a keyup event some time after a keydown event
* is generated when no further activity has been detected.
@@ -679,37 +590,36 @@ static void rc_timer_keyup(unsigned long cookie)
* to allow the input subsystem to do its auto-repeat magic or
* a keyup event might follow immediately after the keydown.
*/
- spin_lock_irqsave(&kt->lock, flags);
+ spin_lock_irqsave(&kt->key_lock, flags);
if (time_is_before_eq_jiffies(kt->keyup_jiffies))
rc_do_keyup(kt, true);
- spin_unlock_irqrestore(&kt->lock, flags);
+ spin_unlock_irqrestore(&kt->key_lock, flags);
}
/**
* rc_repeat() - signals that a key is still pressed
- * @dev: the struct rc_dev descriptor of the device
+ * @kt: the struct rc_keytable descriptor of the keytable
*
- * This routine is used by IR decoders when a repeat message which does
- * not include the necessary bits to reproduce the scancode has been
- * received.
+ * This routine is used when a repeat message which does not include the
+ * necessary bits to reproduce the scancode has been received.
*/
void rc_keytable_repeat(struct rc_keytable *kt)
{
unsigned long flags;
- spin_lock_irqsave(&kt->lock, flags);
+ spin_lock_irqsave(&kt->key_lock, flags);
input_event(kt->idev, EV_MSC, MSC_SCAN, kt->last_scancode);
input_sync(kt->idev);
- if (!kt->keypressed)
+ if (!kt->key_pressed)
goto out;
- kt->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+ kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
out:
- spin_unlock_irqrestore(&kt->lock, flags);
+ spin_unlock_irqrestore(&kt->key_lock, flags);
}
/**
@@ -726,24 +636,32 @@ out:
void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
u64 scancode, u8 toggle, bool autoup)
{
+ struct rc_scan *scan;
+ unsigned index;
+ u32 keycode = KEY_RESERVED;
unsigned long flags;
- u32 keycode;
bool new_event;
- spin_lock_irqsave(&kt->lock, flags);
+ rcu_read_lock();
+ scan = rcu_dereference(kt->scan);
+ index = rc_scancode_to_index(scan, protocol, scancode);
+ if (index < scan->len)
+ keycode = scan->table[index].keycode;
+ rcu_read_unlock();
- keycode = rc_get_keycode(kt, protocol, scancode);
- new_event = !kt->keypressed || kt->last_protocol != protocol ||
- kt->last_scancode != scancode || kt->last_toggle != toggle;
+ spin_lock_irqsave(&kt->key_lock, flags);
+ new_event = !kt->key_pressed || kt->last_protocol != protocol ||
+ kt->last_scancode != scancode ||
+ kt->last_toggle != toggle || kt->last_keycode != keycode;
- if (new_event && kt->keypressed)
+ if (new_event)
rc_do_keyup(kt, false);
input_event(kt->idev, EV_MSC, MSC_SCAN, scancode);
if (new_event && keycode != KEY_RESERVED) {
/* Register a keypress */
- kt->keypressed = true;
+ kt->key_pressed = true;
kt->last_protocol = protocol;
kt->last_scancode = scancode;
kt->last_toggle = toggle;
@@ -757,11 +675,11 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
}
input_sync(kt->idev);
- if (autoup && kt->keypressed) {
- kt->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+ if (autoup && kt->key_pressed) {
+ kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
}
- spin_unlock_irqrestore(&kt->lock, flags);
+ spin_unlock_irqrestore(&kt->key_lock, flags);
}
/**
@@ -810,6 +728,39 @@ static void rc_input_close(struct input_dev *idev)
}
/**
+ * rc_keytable_init() - performs initial setup of a keytable
+ * @dev: the struct rc_dev device descriptor
+ * @from: the struct rc_map to copy entries from
+ * @return: zero on success, or a negative error code
+ *
+ * This function is used to handle table initialization.
+ */
+static int rc_keytable_init(struct rc_keytable *kt,
+ const struct rc_map *from)
+{
+ unsigned size;
+ unsigned i;
+ struct rc_map_table entry;
+
+ size = from ? from->size : 0;
+ kt->scan = kmalloc(rc_scan_size(size), GFP_KERNEL);
+ if (!kt->scan)
+ return -ENOMEM;
+
+ kt->scan->len = 0;
+ for (i = 0; i < size; i++) {
+ entry.protocol = from->scan[i].protocol;
+ entry.scancode = from->scan[i].scancode;
+ if (kt->dev->scanmask)
+ entry.scancode &= kt->dev->scanmask;
+ entry.keycode = from->scan[i].keycode;
+ rc_keytable_add_entry(kt, &entry, true);
+ }
+
+ return 0;
+}
+
+/**
* rc_keytable_create() - creates a new keytable
* @dev: the struct rc_dev device this keytable should belong to
* @name: the userfriendly name of this keymap
@@ -840,8 +791,8 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev,
kt->idev = idev;
kt->dev = dev;
snprintf(kt->name, sizeof(*kt->name), name ? name : "undefined");
- idev->getkeycode = ir_getkeycode;
- idev->setkeycode = ir_setkeycode;
+ idev->getkeycode = rc_keytable_get;
+ idev->setkeycode = rc_keytable_set;
idev->open = rc_input_open;
idev->close = rc_input_close;
set_bit(EV_KEY, idev->evbit);
@@ -858,7 +809,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev,
if (!rc_map || !rc_map->scan || rc_map->size == 0)
goto out;
- error = rc_setkeytable(kt, rc_map);
+ error = rc_keytable_init(kt, rc_map);
if (error)
goto out;
@@ -868,7 +819,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev,
idev->name = dev->input_name;
error = input_register_device(idev);
if (error)
- goto out;
+ goto out_table;
/*
* Default delay of 250ms is too short for some protocols, especially
@@ -885,9 +836,12 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev,
*/
idev->rep[REP_PERIOD] = 125;
- spin_lock_init(&kt->lock);
+ spin_lock_init(&kt->key_lock);
+ mutex_init(&kt->scan_mutex);
return kt;
+out_table:
+ kfree(kt->scan);
out:
input_free_device(idev);
kfree(kt);
@@ -903,8 +857,7 @@ out:
void rc_keytable_destroy(struct rc_keytable *kt)
{
del_timer_sync(&kt->timer_keyup);
- /* Freeing the table should also call the stop callback */
- ir_free_table(&kt->rc_map);
input_unregister_device(kt->idev);
+ kfree(kt->scan);
kfree(kt);
}
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index cd93623..1a38ecc 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -327,35 +327,47 @@ struct rc_dev {
};
/**
+ * struct rc_scan - rcu-friendly scancode<->keycode table
+ * @len: number of elements in the table array
+ * @table: array of struct rc_map_table elements
+ */
+struct rc_scan {
+ unsigned len;
+ struct rc_map_table table[];
+};
+
+/**
* struct rc_keytable - represents one keytable for a rc_dev device
* @node: used to iterate over all keytables for a rc_dev device
* @dev: the rc_dev device this keytable belongs to
* @idev: the input_dev device which belongs to this keytable
* @name: the user-friendly name of this keytable
- * @rc_map: holds the scancode <-> keycode mappings
- * @keypressed: whether a key is currently pressed or not
- * @keyup_jiffies: when the key should be auto-released
- * @timer_keyup: responsible for the auto-release of keys
- * @lock: protects the key state
+ * @scan_mutex: protects @scan against concurrent writers
+ * @scan: the current scancode<->keycode table
+ * @key_lock: protects the key state
+ * @key_pressed: whether a key is currently pressed or not
* @last_keycode: keycode of the last keypress
* @last_protocol: protocol of the last keypress
* @last_scancode: scancode of the last keypress
* @last_toggle: toggle of the last keypress
+ * @timer_keyup: responsible for the auto-release of keys
+ * @keyup_jiffies: when the key should be auto-released
*/
struct rc_keytable {
struct list_head node;
struct rc_dev *dev;
struct input_dev *idev;
char name[RC_KEYTABLE_NAME_SIZE];
- struct rc_map rc_map;
- bool keypressed;
- unsigned long keyup_jiffies;
- struct timer_list timer_keyup;
- spinlock_t lock;
+ struct mutex scan_mutex;
+ struct rc_scan __rcu *scan;
+ spinlock_t key_lock;
+ bool key_pressed;
u32 last_keycode;
enum rc_type last_protocol;
u64 last_scancode;
u8 last_toggle;
+ struct timer_list timer_keyup;
+ unsigned long keyup_jiffies;
};
#define to_rc_dev(d) container_of(d, struct rc_dev, dev)
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 31/43] rc-core: allow empty keymaps
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (29 preceding siblings ...)
2012-05-23 9:44 ` [PATCH 30/43] rc-core: make keytable RCU-friendly David Härdeman
@ 2012-05-23 9:44 ` David Härdeman
2012-05-23 9:44 ` [PATCH 32/43] rc-core: split IR raw handling to a separate module David Härdeman
` (12 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:44 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Remove the RC_MAP_EMPTY hack and instead allow for empty keymaps.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/dvb/dvb-usb/af9015.c | 4 ----
drivers/media/dvb/dvb-usb/af9035.c | 1 -
drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 4 +---
drivers/media/dvb/dvb-usb/rtl28xxu.c | 2 --
drivers/media/rc/gpio-ir-recv.c | 1 -
drivers/media/rc/rc-keytable.c | 13 ++++---------
drivers/media/rc/rc-loopback.c | 1 -
drivers/media/rc/rc-main.c | 17 +----------------
drivers/media/video/cx88/cx88-input.c | 6 ------
drivers/media/video/ir-kbd-i2c.c | 4 +---
drivers/media/video/ivtv/ivtv-i2c.c | 2 +-
include/media/rc-map.h | 1 -
12 files changed, 8 insertions(+), 48 deletions(-)
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 4733044..b82e235 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -809,10 +809,6 @@ static void af9015_set_remote_config(struct usb_device *udev,
}
}
- /* finally load "empty" just for leaving IR receiver enabled */
- if (!props->rc.core.rc_codes)
- props->rc.core.rc_codes = RC_MAP_EMPTY;
-
return;
}
diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c
index 42094e1..62714ad 100644
--- a/drivers/media/dvb/dvb-usb/af9035.c
+++ b/drivers/media/dvb/dvb-usb/af9035.c
@@ -1061,7 +1061,6 @@ static struct dvb_usb_device_properties af9035_properties[] = {
.rc_query = NULL,
.rc_interval = AF9035_POLL,
.allowed_protos = RC_TYPE_UNKNOWN,
- .rc_codes = RC_MAP_EMPTY,
},
.num_device_descs = 5,
.devices = {
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 41bacff..909e95c 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -313,10 +313,8 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query)
d->props.rc.mode = DVB_RC_LEGACY;
- else if (d->props.rc.core.rc_codes)
- d->props.rc.mode = DVB_RC_CORE;
else
- return 0;
+ d->props.rc.mode = DVB_RC_CORE;
usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c
index 9dbde0a..8d67bc6 100644
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.c
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c
@@ -819,7 +819,6 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
.rc_query = rtl2831u_rc_query,
.rc_interval = 400,
.allowed_protos = RC_BIT_NEC,
- .rc_codes = RC_MAP_EMPTY,
},
.i2c_algo = &rtl28xxu_i2c_algo,
@@ -881,7 +880,6 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
.rc_query = rtl2832u_rc_query,
.rc_interval = 400,
.allowed_protos = RC_BIT_NEC,
- .rc_codes = RC_MAP_EMPTY,
},
.i2c_algo = &rtl28xxu_i2c_algo,
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 478b2e9..3ee7455 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -87,7 +87,6 @@ static int __devinit gpio_ir_recv_probe(struct platform_device *pdev)
rcdev->input_name = GPIO_IR_DEVICE_NAME;
rcdev->input_id.bustype = BUS_HOST;
rcdev->driver_name = GPIO_IR_DRIVER_NAME;
- rcdev->map_name = RC_MAP_EMPTY;
gpio_dev->rcdev = rcdev;
gpio_dev->gpio_nr = pdata->gpio_nr;
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index d6e68d0..d5b1d88 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -54,6 +54,9 @@ struct rc_map *rc_map_get(const char *name)
struct rc_map_list *map;
+ if (!name)
+ return NULL;
+
map = seek_rc_map(name);
#ifdef MODULE
if (!map) {
@@ -777,7 +780,6 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev,
{
struct rc_keytable *kt;
struct input_dev *idev = NULL;
- struct rc_map *rc_map = NULL;
int error;
kt = kzalloc(sizeof(*kt), GFP_KERNEL);
@@ -802,14 +804,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev,
input_set_drvdata(idev, kt);
setup_timer(&kt->timer_keyup, rc_timer_keyup, (unsigned long)kt);
- if (map_name)
- rc_map = rc_map_get(map_name);
- if (!rc_map)
- rc_map = rc_map_get(RC_MAP_EMPTY);
- if (!rc_map || !rc_map->scan || rc_map->size == 0)
- goto out;
-
- error = rc_keytable_init(kt, rc_map);
+ error = rc_keytable_init(kt, rc_map_get(map_name));
if (error)
goto out;
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index de9a75e..af64d15 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -218,7 +218,6 @@ static int __init loop_init(void)
rc->input_id.bustype = BUS_VIRTUAL;
rc->input_id.version = 1;
rc->driver_name = DRIVER_NAME;
- rc->map_name = RC_MAP_EMPTY;
rc->priv = &loopdev;
rc->driver_type = RC_DRIVER_IR_RAW;
rc->allowed_protos = RC_BIT_ALL;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index a9c7226..4edaffb 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -543,7 +543,7 @@ int rc_register_device(struct rc_dev *dev)
int rc;
unsigned int i;
- if (!dev || !dev->map_name)
+ if (!dev)
return -EINVAL;
rc = mutex_lock_interruptible(&rc_dev_table_mutex);
@@ -1119,19 +1119,6 @@ static const struct file_operations rc_fops = {
#endif
};
-static struct rc_map_table empty[] = {
- { RC_TYPE_OTHER, 0x2a, KEY_COFFEE },
-};
-
-static struct rc_map_list empty_map = {
- .map = {
- .scan = empty,
- .size = ARRAY_SIZE(empty),
- .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
- .name = RC_MAP_EMPTY,
- }
-};
-
static int __init rc_core_init(void)
{
int ret;
@@ -1151,7 +1138,6 @@ static int __init rc_core_init(void)
goto chrdev;
}
- rc_map_register(&empty_map);
return 0;
chrdev:
@@ -1164,7 +1150,6 @@ static void __exit rc_core_exit(void)
{
class_unregister(&rc_class);
unregister_chrdev(rc_major, "rc");
-rc_map_unregister(&empty_map);
}
subsys_initcall(rc_core_init);
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index b1922f0..2962ef7 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -423,11 +423,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
break;
}
- if (!ir_codes) {
- err = -ENODEV;
- goto err_out_free;
- }
-
/*
* The usage of mask_keycode were very convenient, due to several
* reasons. Among others, the scancode tables were using the scancode
@@ -596,7 +591,6 @@ void cx88_i2c_init_ir(struct cx88_core *core)
core->init_data.name = "cx88 Leadtek PVR 2000 remote";
core->init_data.type = RC_BIT_UNKNOWN;
core->init_data.get_key = get_key_pvr2000;
- core->init_data.ir_codes = RC_MAP_EMPTY;
break;
}
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 86c53fa..3e0fa74 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -311,7 +311,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
name = "Pixelview";
ir->get_key = get_key_pixelview;
rc_type = RC_BIT_OTHER;
- ir_codes = RC_MAP_EMPTY;
break;
case 0x18:
case 0x1f:
@@ -325,7 +324,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
name = "KNC One";
ir->get_key = get_key_knc1;
rc_type = RC_BIT_OTHER;
- ir_codes = RC_MAP_EMPTY;
break;
case 0x6b:
name = "FusionHDTV";
@@ -402,7 +400,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
ir->rc = rc;
/* Make sure we are all setup before going on */
- if (!name || !ir->get_key || !rc_type || !ir_codes) {
+ if (!name || !ir->get_key || !rc_type) {
dprintk(1, ": Unsupported device at address 0x%02x\n",
addr);
err = -ENODEV;
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 46e262b..5b95586 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -221,7 +221,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
init_data->get_key = get_key_adaptec;
init_data->name = itv->card_name;
/* FIXME: The protocol and RC_MAP needs to be corrected */
- init_data->ir_codes = RC_MAP_EMPTY;
+ /* init_data->ir_codes = RC_MAP_? */
init_data->type = RC_BIT_UNKNOWN;
break;
}
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 5737c65..183d45c 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -135,7 +135,6 @@ void rc_map_init(void);
#define RC_MAP_DM1105_NEC "rc-dm1105-nec"
#define RC_MAP_DNTV_LIVE_DVBT_PRO "rc-dntv-live-dvbt-pro"
#define RC_MAP_DNTV_LIVE_DVB_T "rc-dntv-live-dvb-t"
-#define RC_MAP_EMPTY "rc-empty"
#define RC_MAP_EM_TERRATEC "rc-em-terratec"
#define RC_MAP_ENCORE_ENLTV2 "rc-encore-enltv2"
#define RC_MAP_ENCORE_ENLTV_FM53 "rc-encore-enltv-fm53"
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 32/43] rc-core: split IR raw handling to a separate module
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (30 preceding siblings ...)
2012-05-23 9:44 ` [PATCH 31/43] rc-core: allow empty keymaps David Härdeman
@ 2012-05-23 9:44 ` David Härdeman
2012-05-23 9:44 ` [PATCH 33/43] rc-ir-raw: simplify locking David Härdeman
` (11 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:44 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Move drivers/media/rc/ir-raw.c to drivers/media/rc/rc-ir-raw.c and make it
a separate kernel module (rc-ir-raw.ko to make it clearer that it belongs to
the rc-* family).
Drivers which use IR decoding must use these functions:
rc_register_ir_raw_device()
rc_unregister_ir_raw_device()
instead of:
rc_register_device()
rc_unregister_device()
This allows scancode drivers to skip lots of unnecessary functionality.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/dvb/dvb-usb/Kconfig | 2
drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 7
drivers/media/dvb/dvb-usb/dvb-usb.h | 2
drivers/media/dvb/siano/Kconfig | 2
drivers/media/dvb/siano/smsir.c | 4
drivers/media/dvb/siano/smsir.h | 2
drivers/media/rc/Kconfig | 54 +++-
drivers/media/rc/Makefile | 3
drivers/media/rc/ene_ir.c | 6
drivers/media/rc/fintek-cir.c | 6
drivers/media/rc/gpio-ir-recv.c | 8 -
drivers/media/rc/ir-raw.c | 372 ---------------------------
drivers/media/rc/ite-cir.c | 6
drivers/media/rc/mceusb.c | 6
drivers/media/rc/nuvoton-cir.c | 6
drivers/media/rc/rc-core-priv.h | 3
drivers/media/rc/rc-ir-raw.c | 379 +++++++++++++++++++++++++++
drivers/media/rc/rc-loopback.c | 6
drivers/media/rc/rc-main.c | 39 +--
drivers/media/rc/redrat3.c | 6
drivers/media/rc/streamzap.c | 6
drivers/media/rc/winbond-cir.c | 6
drivers/media/video/cx23885/Kconfig | 2
drivers/media/video/cx23885/cx23885-input.c | 6
drivers/media/video/cx23885/cx23888-ir.c | 2
drivers/media/video/cx25840/cx25840-ir.c | 2
drivers/media/video/cx88/Kconfig | 2
drivers/media/video/cx88/cx88-input.c | 6
drivers/media/video/saa7134/Kconfig | 2
drivers/media/video/saa7134/saa7134-input.c | 4
drivers/media/video/saa7134/saa7134.h | 2
include/media/rc-core.h | 49 ---
include/media/rc-ir-raw.h | 68 +++++
33 files changed, 557 insertions(+), 519 deletions(-)
delete mode 100644 drivers/media/rc/ir-raw.c
create mode 100644 drivers/media/rc/rc-ir-raw.c
create mode 100644 include/media/rc-ir-raw.h
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index a269493..e9c94f2 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -1,6 +1,6 @@
config DVB_USB
tristate "Support for various USB DVB devices"
- depends on DVB_CORE && USB && I2C && RC_CORE
+ depends on DVB_CORE && USB && I2C && RC_CORE && RC_IR_RAW
help
By enabling this you will be able to choose the various supported
USB1.1 and USB2.0 DVB devices.
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 909e95c..6f138c3 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -280,7 +280,10 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
dev->dev.parent = &d->udev->dev;
dev->priv = d;
- err = rc_register_device(dev);
+ if (dev->driver_type == RC_DRIVER_IR_RAW)
+ err = rc_register_ir_raw_device(dev);
+ else
+ err = rc_register_device(dev);
if (err < 0) {
rc_free_device(dev);
return err;
@@ -341,6 +344,8 @@ int dvb_usb_remote_exit(struct dvb_usb_device *d)
cancel_delayed_work_sync(&d->rc_query_work);
if (d->props.rc.mode == DVB_RC_LEGACY)
input_unregister_device(d->input_dev);
+ else if (d->rc_dev->driver_type == RC_DRIVER_IR_RAW)
+ rc_unregister_ir_raw_device(d->rc_dev);
else
rc_unregister_device(d->rc_dev);
}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index ed886ae..1ce0bb8 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -14,7 +14,7 @@
#include <linux/usb.h>
#include <linux/firmware.h>
#include <linux/mutex.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#include "dvb_frontend.h"
#include "dvb_demux.h"
diff --git a/drivers/media/dvb/siano/Kconfig b/drivers/media/dvb/siano/Kconfig
index bc6456e..fa2923f 100644
--- a/drivers/media/dvb/siano/Kconfig
+++ b/drivers/media/dvb/siano/Kconfig
@@ -4,7 +4,7 @@
config SMS_SIANO_MDTV
tristate "Siano SMS1xxx based MDTV receiver"
- depends on DVB_CORE && RC_CORE && HAS_DMA
+ depends on DVB_CORE && RC_CORE && RC_IR_RAW && HAS_DMA
---help---
Choose Y or M here if you have MDTV receiver with a Siano chipset.
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
index b8c5cad..c9a627d 100644
--- a/drivers/media/dvb/siano/smsir.c
+++ b/drivers/media/dvb/siano/smsir.c
@@ -94,7 +94,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
sms_log("Input device (IR) %s is set for key events", dev->input_name);
- err = rc_register_device(dev);
+ err = rc_register_ir_raw_device(dev);
if (err < 0) {
sms_err("Failed to register device");
rc_free_device(dev);
@@ -108,7 +108,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
void sms_ir_exit(struct smscore_device_t *coredev)
{
if (coredev->ir.dev)
- rc_unregister_device(coredev->ir.dev);
+ rc_unregister_ir_raw_device(coredev->ir.dev);
sms_log("");
}
diff --git a/drivers/media/dvb/siano/smsir.h b/drivers/media/dvb/siano/smsir.h
index ae92b3a..b583ce9 100644
--- a/drivers/media/dvb/siano/smsir.h
+++ b/drivers/media/dvb/siano/smsir.h
@@ -28,7 +28,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define __SMS_IR_H__
#include <linux/input.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#define IR_DEFAULT_TIMEOUT 100
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 090872b..851d927 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -26,9 +26,25 @@ config LIRC
source "drivers/media/rc/keymaps/Kconfig"
+menuconfig RC_IR_RAW
+ tristate "Remote Controller raw IR adapters"
+ depends on RC_CORE
+ default RC_CORE
+ ---help---
+ Enable support for raw InfraRed Remote Controllers.
+ These devices measure the pulse/space timings of
+ IR signals and rely on software decoding of the
+ signal.
+
+ Enable this option if you have a video capture board even
+ if you don't need IR, as otherwise, you may not be able to
+ compile the driver for your adapter.
+
+if RC_IR_RAW
+
config IR_NEC_DECODER
tristate "Enable IR raw decoder for the NEC protocol"
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
select BITREVERSE
default y
@@ -38,7 +54,7 @@ config IR_NEC_DECODER
config IR_RC5_DECODER
tristate "Enable IR raw decoder for the RC-5 protocol"
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
select BITREVERSE
default y
@@ -48,7 +64,7 @@ config IR_RC5_DECODER
config IR_RC6_DECODER
tristate "Enable IR raw decoder for the RC6 protocol"
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
select BITREVERSE
default y
@@ -58,7 +74,7 @@ config IR_RC6_DECODER
config IR_JVC_DECODER
tristate "Enable IR raw decoder for the JVC protocol"
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
select BITREVERSE
default y
@@ -68,7 +84,7 @@ config IR_JVC_DECODER
config IR_SONY_DECODER
tristate "Enable IR raw decoder for the Sony protocol"
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
select BITREVERSE
default y
@@ -78,7 +94,7 @@ config IR_SONY_DECODER
config IR_SANYO_DECODER
tristate "Enable IR raw decoder for the Sanyo protocol"
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
default y
---help---
@@ -88,7 +104,7 @@ config IR_SANYO_DECODER
config IR_MCE_KBD_DECODER
tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
select BITREVERSE
default y
@@ -99,7 +115,7 @@ config IR_MCE_KBD_DECODER
config IR_LIRC_CODEC
tristate "Enable IR to LIRC bridge"
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
depends on LIRC
default y
@@ -107,6 +123,8 @@ config IR_LIRC_CODEC
Enable this option to pass raw IR to and from userspace via
the LIRC interface.
+endif #RC_IR_RAW
+
config RC_ATI_REMOTE
tristate "ATI / X10 based USB RF remote controls"
depends on USB_ARCH_HAS_HCD
@@ -129,7 +147,7 @@ config RC_ATI_REMOTE
config IR_ENE
tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)"
depends on PNP
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
---help---
Say Y here to enable support for integrated infrared receiver
/transceiver made by ENE.
@@ -155,7 +173,7 @@ config IR_IMON
config IR_MCEUSB
tristate "Windows Media Center Ed. eHome Infrared Transceiver"
depends on USB_ARCH_HAS_HCD
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
select USB
---help---
Say Y here if you want to use a Windows Media Center Edition
@@ -167,7 +185,7 @@ config IR_MCEUSB
config IR_ITE_CIR
tristate "ITE Tech Inc. IT8712/IT8512 Consumer Infrared Transceiver"
depends on PNP
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
---help---
Say Y here to enable support for integrated infrared receivers
/transceivers made by ITE Tech Inc. These are found in
@@ -180,7 +198,7 @@ config IR_ITE_CIR
config IR_FINTEK
tristate "Fintek Consumer Infrared Transceiver"
depends on PNP
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
---help---
Say Y here to enable support for integrated infrared receiver
/transciever made by Fintek. This chip is found on assorted
@@ -192,7 +210,7 @@ config IR_FINTEK
config IR_NUVOTON
tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
depends on PNP
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
---help---
Say Y here to enable support for integrated infrared receiver
/transciever made by Nuvoton (formerly Winbond). This chip is
@@ -205,7 +223,7 @@ config IR_NUVOTON
config IR_REDRAT3
tristate "RedRat3 IR Transceiver"
depends on USB_ARCH_HAS_HCD
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
select USB
---help---
Say Y here if you want to use a RedRat3 Infrared Transceiver.
@@ -216,7 +234,7 @@ config IR_REDRAT3
config IR_STREAMZAP
tristate "Streamzap PC Remote IR Receiver"
depends on USB_ARCH_HAS_HCD
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
select USB
---help---
Say Y here if you want to use a Streamzap PC Remote
@@ -228,7 +246,7 @@ config IR_STREAMZAP
config IR_WINBOND_CIR
tristate "Winbond IR remote control"
depends on X86 && PNP
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
select NEW_LEDS
select LEDS_CLASS
select LEDS_TRIGGERS
@@ -244,7 +262,7 @@ config IR_WINBOND_CIR
config RC_LOOPBACK
tristate "Remote Control Loopback Driver"
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
---help---
Say Y here if you want support for the remote control loopback
driver which allows TX data to be sent back as RX data.
@@ -257,7 +275,7 @@ config RC_LOOPBACK
config IR_GPIO_CIR
tristate "GPIO IR remote control"
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
---help---
Say Y if you want to use GPIO based IR Receiver.
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index f470a3f..22eda72 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -1,9 +1,10 @@
-rc-core-objs := rc-main.o rc-keytable.o ir-raw.o
+rc-core-objs := rc-main.o rc-keytable.o
obj-y += keymaps/
obj-$(CONFIG_RC_CORE) += rc-core.o
obj-$(CONFIG_LIRC) += lirc_dev.o
+obj-$(CONFIG_RC_CORE) += rc-ir-raw.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
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index ec09646..eb107e8 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -39,7 +39,7 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#include "ene_ir.h"
static int sample_period;
@@ -1073,7 +1073,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
goto error;
}
- error = rc_register_device(rdev);
+ error = rc_register_ir_raw_device(rdev);
if (error < 0)
goto error;
@@ -1103,7 +1103,7 @@ static void ene_remove(struct pnp_dev *pnp_dev)
free_irq(dev->irq, dev);
release_region(dev->hw_io, ENE_IO_SIZE);
- rc_unregister_device(dev->rdev);
+ rc_unregister_ir_raw_device(dev->rdev);
kfree(dev);
}
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index f684dd8..01e6ef8 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -30,7 +30,7 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#include <linux/pci_ids.h>
#include "fintek-cir.h"
@@ -558,7 +558,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
FINTEK_DRIVER_NAME, (void *)fintek))
goto failure2;
- ret = rc_register_device(rdev);
+ ret = rc_register_ir_raw_device(rdev);
if (ret)
goto failure3;
@@ -598,7 +598,7 @@ static void __devexit fintek_remove(struct pnp_dev *pdev)
free_irq(fintek->cir_irq, fintek);
release_region(fintek->cir_addr, fintek->cir_port_len);
- rc_unregister_device(fintek->rdev);
+ rc_unregister_ir_raw_device(fintek->rdev);
kfree(fintek);
}
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 3ee7455..23141b0 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -18,7 +18,7 @@
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#include <media/gpio-ir-recv.h>
#define GPIO_IR_DRIVER_NAME "gpio-rc-recv"
@@ -99,7 +99,7 @@ static int __devinit gpio_ir_recv_probe(struct platform_device *pdev)
if (rc < 0)
goto err_gpio_direction_input;
- rc = rc_register_device(rcdev);
+ rc = rc_register_ir_raw_device(rcdev);
if (rc < 0) {
dev_err(&pdev->dev, "failed to register rc device\n");
goto err_register_rc_device;
@@ -118,7 +118,7 @@ static int __devinit gpio_ir_recv_probe(struct platform_device *pdev)
err_request_irq:
platform_set_drvdata(pdev, NULL);
- rc_unregister_device(rcdev);
+ rc_unregister_ir_raw_device(rcdev);
err_register_rc_device:
err_gpio_direction_input:
gpio_free(pdata->gpio_nr);
@@ -136,7 +136,7 @@ static int __devexit gpio_ir_recv_remove(struct platform_device *pdev)
free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
platform_set_drvdata(pdev, NULL);
- rc_unregister_device(gpio_dev->rcdev);
+ rc_unregister_ir_raw_device(gpio_dev->rcdev);
gpio_free(gpio_dev->gpio_nr);
rc_free_device(gpio_dev->rcdev);
kfree(gpio_dev);
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
deleted file mode 100644
index 6ef1510..0000000
--- a/drivers/media/rc/ir-raw.c
+++ /dev/null
@@ -1,372 +0,0 @@
-/* ir-raw.c - handle IR pulse/space events
- *
- * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/export.h>
-#include <linux/kthread.h>
-#include <linux/mutex.h>
-#include <linux/kmod.h>
-#include <linux/sched.h>
-#include <linux/freezer.h>
-#include "rc-core-priv.h"
-
-/* Define the max number of pulse/space transitions to buffer */
-#define MAX_IR_EVENT_SIZE 512
-
-/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
-static LIST_HEAD(ir_raw_client_list);
-
-/* Used to handle IR raw handler extensions */
-static DEFINE_MUTEX(ir_raw_handler_lock);
-static LIST_HEAD(ir_raw_handler_list);
-static u64 available_protocols;
-
-#ifdef MODULE
-/* Used to load the decoders */
-static struct work_struct wq_load;
-#endif
-
-static int ir_raw_event_thread(void *data)
-{
- struct ir_raw_event ev;
- struct ir_raw_handler *handler;
- struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
- int retval;
-
- while (!kthread_should_stop()) {
-
- spin_lock_irq(&raw->lock);
- retval = kfifo_len(&raw->kfifo);
-
- if (retval < sizeof(ev)) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (kthread_should_stop())
- set_current_state(TASK_RUNNING);
-
- spin_unlock_irq(&raw->lock);
- schedule();
- continue;
- }
-
- retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
- spin_unlock_irq(&raw->lock);
-
- mutex_lock(&ir_raw_handler_lock);
- list_for_each_entry(handler, &ir_raw_handler_list, list)
- handler->decode(raw->dev, ev);
- raw->prev_ev = ev;
- mutex_unlock(&ir_raw_handler_lock);
- }
-
- return 0;
-}
-
-/**
- * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
- * @dev: the struct rc_dev device descriptor
- * @ev: the struct ir_raw_event descriptor of the pulse/space
- *
- * This routine (which may be called from an interrupt context) stores a
- * pulse/space duration for the raw ir decoding state machines. Pulses are
- * signalled as positive values and spaces as negative values. A zero value
- * will reset the decoding state machines.
- */
-int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
-{
- if (!dev->raw)
- return -EINVAL;
-
- IR_dprintk(2, "sample: (%05dus %s)\n",
- TO_US(ev->duration), TO_STR(ev->pulse));
-
- if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
- return -ENOMEM;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ir_raw_event_store);
-
-/**
- * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space
- * @dev: the struct rc_dev device descriptor
- * @type: the type of the event that has occurred
- *
- * This routine (which may be called from an interrupt context) is used to
- * store the beginning of an ir pulse or space (or the start/end of ir
- * reception) for the raw ir decoding state machines. This is used by
- * hardware which does not provide durations directly but only interrupts
- * (or similar events) on state change.
- */
-int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
-{
- ktime_t now;
- s64 delta; /* ns */
- DEFINE_IR_RAW_EVENT(ev);
- int rc = 0;
-
- if (!dev->raw)
- return -EINVAL;
-
- now = ktime_get();
- delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
-
- /* Check for a long duration since last event or if we're
- * being called for the first time, note that delta can't
- * possibly be negative.
- */
- if (delta > MS_TO_NS(500) || !dev->raw->last_type)
- type |= IR_START_EVENT;
- else
- ev.duration = delta;
-
- if (type & IR_START_EVENT)
- ir_raw_event_reset(dev);
- else if (dev->raw->last_type & IR_SPACE) {
- ev.pulse = false;
- rc = ir_raw_event_store(dev, &ev);
- } else if (dev->raw->last_type & IR_PULSE) {
- ev.pulse = true;
- rc = ir_raw_event_store(dev, &ev);
- } else
- return 0;
-
- dev->raw->last_event = now;
- dev->raw->last_type = type;
- return rc;
-}
-EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
-
-/**
- * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing
- * @dev: the struct rc_dev device descriptor
- * @type: the type of the event that has occurred
- *
- * This routine (which may be called from an interrupt context) works
- * in similar manner to ir_raw_event_store_edge.
- * This routine is intended for devices with limited internal buffer
- * It automerges samples of same type, and handles timeouts
- */
-int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
-{
- if (!dev->raw)
- return -EINVAL;
-
- /* Ignore spaces in idle mode */
- if (dev->idle && !ev->pulse)
- return 0;
- else if (dev->idle)
- ir_raw_event_set_idle(dev, false);
-
- if (!dev->raw->this_ev.duration)
- dev->raw->this_ev = *ev;
- else if (ev->pulse == dev->raw->this_ev.pulse)
- dev->raw->this_ev.duration += ev->duration;
- else {
- ir_raw_event_store(dev, &dev->raw->this_ev);
- dev->raw->this_ev = *ev;
- }
-
- /* Enter idle mode if nessesary */
- if (!ev->pulse && dev->timeout &&
- dev->raw->this_ev.duration >= dev->timeout)
- ir_raw_event_set_idle(dev, true);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
-
-/**
- * ir_raw_event_set_idle() - provide hint to rc-core when the device is idle or not
- * @dev: the struct rc_dev device descriptor
- * @idle: whether the device is idle or not
- */
-void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
-{
- if (!dev->raw)
- return;
-
- IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
-
- if (idle) {
- dev->raw->this_ev.timeout = true;
- ir_raw_event_store(dev, &dev->raw->this_ev);
- init_ir_raw_event(&dev->raw->this_ev);
- }
-
- if (dev->s_idle)
- dev->s_idle(dev, idle);
-
- dev->idle = idle;
-}
-EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
-
-/**
- * ir_raw_event_handle() - schedules the decoding of stored ir data
- * @dev: the struct rc_dev device descriptor
- *
- * This routine will tell rc-core to start decoding stored ir data.
- */
-void ir_raw_event_handle(struct rc_dev *dev)
-{
- unsigned long flags;
-
- if (!dev->raw)
- return;
-
- spin_lock_irqsave(&dev->raw->lock, flags);
- wake_up_process(dev->raw->thread);
- spin_unlock_irqrestore(&dev->raw->lock, flags);
-}
-EXPORT_SYMBOL_GPL(ir_raw_event_handle);
-
-/* used internally by the sysfs interface */
-u64
-ir_raw_get_allowed_protocols(void)
-{
- u64 protocols;
- mutex_lock(&ir_raw_handler_lock);
- protocols = available_protocols;
- mutex_unlock(&ir_raw_handler_lock);
- return protocols;
-}
-
-/*
- * Used to (un)register raw event clients
- */
-int ir_raw_event_register(struct rc_dev *dev)
-{
- int rc;
- struct ir_raw_handler *handler;
-
- if (!dev)
- return -EINVAL;
-
- dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL);
- if (!dev->raw)
- return -ENOMEM;
-
- dev->raw->dev = dev;
- dev->enabled_protocols = ~0;
- rc = kfifo_alloc(&dev->raw->kfifo,
- sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
- GFP_KERNEL);
- if (rc < 0)
- goto out;
-
- spin_lock_init(&dev->raw->lock);
- 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;
- }
-
- mutex_lock(&ir_raw_handler_lock);
- list_add_tail(&dev->raw->list, &ir_raw_client_list);
- list_for_each_entry(handler, &ir_raw_handler_list, list)
- if (handler->raw_register)
- handler->raw_register(dev);
- mutex_unlock(&ir_raw_handler_lock);
-
- return 0;
-
-out:
- kfree(dev->raw);
- dev->raw = NULL;
- return rc;
-}
-
-void ir_raw_event_unregister(struct rc_dev *dev)
-{
- struct ir_raw_handler *handler;
-
- if (!dev || !dev->raw)
- return;
-
- kthread_stop(dev->raw->thread);
-
- mutex_lock(&ir_raw_handler_lock);
- list_del(&dev->raw->list);
- list_for_each_entry(handler, &ir_raw_handler_list, list)
- if (handler->raw_unregister)
- handler->raw_unregister(dev);
- mutex_unlock(&ir_raw_handler_lock);
-
- kfifo_free(&dev->raw->kfifo);
- kfree(dev->raw);
- dev->raw = NULL;
-}
-
-/*
- * Extension interface - used to register the IR decoders
- */
-
-int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
-{
- struct ir_raw_event_ctrl *raw;
-
- mutex_lock(&ir_raw_handler_lock);
- list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
- if (ir_raw_handler->raw_register)
- list_for_each_entry(raw, &ir_raw_client_list, list)
- ir_raw_handler->raw_register(raw->dev);
- available_protocols |= ir_raw_handler->protocols;
- mutex_unlock(&ir_raw_handler_lock);
-
- return 0;
-}
-EXPORT_SYMBOL(ir_raw_handler_register);
-
-void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
-{
- struct ir_raw_event_ctrl *raw;
-
- mutex_lock(&ir_raw_handler_lock);
- list_del(&ir_raw_handler->list);
- if (ir_raw_handler->raw_unregister)
- list_for_each_entry(raw, &ir_raw_client_list, list)
- ir_raw_handler->raw_unregister(raw->dev);
- available_protocols &= ~ir_raw_handler->protocols;
- mutex_unlock(&ir_raw_handler_lock);
-}
-EXPORT_SYMBOL(ir_raw_handler_unregister);
-
-#ifdef MODULE
-static void init_decoders(struct work_struct *work)
-{
- /* Load the decoder modules */
-
- load_nec_decode();
- load_rc5_decode();
- load_rc6_decode();
- load_jvc_decode();
- load_sony_decode();
- load_sanyo_decode();
- load_mce_kbd_decode();
- load_lirc_codec();
-
- /* If needed, we may later add some init code. In this case,
- it is needed to change the CONFIG_MODULE test at rc-core.h
- */
-}
-#endif
-
-void ir_raw_init(void)
-{
-#ifdef MODULE
- INIT_WORK(&wq_load, init_decoders);
- schedule_work(&wq_load);
-#endif
-}
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 5abb7c3..6721767 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -40,7 +40,7 @@
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/bitops.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#include <linux/pci_ids.h>
#include "ite-cir.h"
@@ -1597,7 +1597,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
ITE_DRIVER_NAME, (void *)itdev))
goto failure2;
- ret = rc_register_device(rdev);
+ ret = rc_register_ir_raw_device(rdev);
if (ret)
goto failure3;
@@ -1635,7 +1635,7 @@ static void __devexit ite_remove(struct pnp_dev *pdev)
free_irq(dev->cir_irq, dev);
release_region(dev->cir_addr, dev->params.io_region_size);
- rc_unregister_device(dev->rdev);
+ rc_unregister_ir_raw_device(dev->rdev);
kfree(dev);
}
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index c60ac4e..e9dda87 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -43,7 +43,7 @@
#include <linux/usb.h>
#include <linux/usb/input.h>
#include <linux/pm_wakeup.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#define DRIVER_VERSION "1.92"
#define DRIVER_AUTHOR "Jarod Wilson <jarod@redhat.com>"
@@ -1189,7 +1189,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
rc->map_name = mceusb_model[ir->model].rc_map ?
mceusb_model[ir->model].rc_map : RC_MAP_RC6_MCE;
- ret = rc_register_device(rc);
+ ret = rc_register_ir_raw_device(rc);
if (ret < 0) {
dev_err(dev, "remote dev registration failed\n");
goto out;
@@ -1378,7 +1378,7 @@ static void __devexit mceusb_dev_disconnect(struct usb_interface *intf)
return;
ir->usbdev = NULL;
- rc_unregister_device(ir->rc);
+ rc_unregister_ir_raw_device(ir->rc);
usb_kill_urb(ir->urb_in);
usb_free_urb(ir->urb_in);
usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 447f0d0..0548db4 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -32,7 +32,7 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#include <linux/pci_ids.h>
#include "nuvoton-cir.h"
@@ -1090,7 +1090,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
NVT_DRIVER_NAME, (void *)nvt))
goto failure4;
- ret = rc_register_device(rdev);
+ ret = rc_register_ir_raw_device(rdev);
if (ret)
goto failure5;
@@ -1138,7 +1138,7 @@ static void __devexit nvt_remove(struct pnp_dev *pdev)
release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
- rc_unregister_device(nvt->rdev);
+ rc_unregister_ir_raw_device(nvt->rdev);
kfree(nvt);
}
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 8006c2e..b2a5d99 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -19,6 +19,8 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
+
struct ir_raw_handler {
struct list_head list;
@@ -142,7 +144,6 @@ static inline bool is_timing_event(struct ir_raw_event ev)
/*
* Routines from rc-raw.c to be used internally and by decoders
*/
-u64 ir_raw_get_allowed_protocols(void);
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);
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
new file mode 100644
index 0000000..a0d3508
--- /dev/null
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -0,0 +1,379 @@
+/* ir-raw.c - handle IR pulse/space events
+ *
+ * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/kmod.h>
+#include <linux/sched.h>
+#include <linux/freezer.h>
+#include <linux/module.h>
+#include <media/rc-ir-raw.h>
+
+#include "rc-core-priv.h"
+
+/* Define the max number of pulse/space transitions to buffer */
+#define MAX_IR_EVENT_SIZE 512
+
+/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
+static LIST_HEAD(ir_raw_client_list);
+
+/* Used to handle IR raw handler extensions */
+static DEFINE_MUTEX(ir_raw_handler_lock);
+static LIST_HEAD(ir_raw_handler_list);
+static u64 available_protocols;
+
+static int ir_raw_event_thread(void *data)
+{
+ struct ir_raw_event ev;
+ struct ir_raw_handler *handler;
+ struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
+ int retval;
+
+ while (!kthread_should_stop()) {
+
+ spin_lock_irq(&raw->lock);
+ retval = kfifo_len(&raw->kfifo);
+
+ if (retval < sizeof(ev)) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (kthread_should_stop())
+ set_current_state(TASK_RUNNING);
+
+ spin_unlock_irq(&raw->lock);
+ schedule();
+ continue;
+ }
+
+ retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
+ spin_unlock_irq(&raw->lock);
+
+ mutex_lock(&ir_raw_handler_lock);
+ list_for_each_entry(handler, &ir_raw_handler_list, list)
+ handler->decode(raw->dev, ev);
+ raw->prev_ev = ev;
+ mutex_unlock(&ir_raw_handler_lock);
+ }
+
+ return 0;
+}
+
+/**
+ * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
+ * @dev: the struct rc_dev device descriptor
+ * @ev: the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This routine (which may be called from an interrupt context) stores a
+ * pulse/space duration for the raw ir decoding state machines. Pulses are
+ * signalled as positive values and spaces as negative values. A zero value
+ * will reset the decoding state machines.
+ */
+int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
+{
+ if (!dev->raw)
+ return -EINVAL;
+
+ IR_dprintk(2, "sample: (%05dus %s)\n",
+ TO_US(ev->duration), TO_STR(ev->pulse));
+
+ if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
+ return -ENOMEM;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_store);
+
+/**
+ * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space
+ * @dev: the struct rc_dev device descriptor
+ * @type: the type of the event that has occurred
+ *
+ * This routine (which may be called from an interrupt context) is used to
+ * store the beginning of an ir pulse or space (or the start/end of ir
+ * reception) for the raw ir decoding state machines. This is used by
+ * hardware which does not provide durations directly but only interrupts
+ * (or similar events) on state change.
+ */
+int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
+{
+ ktime_t now;
+ s64 delta; /* ns */
+ DEFINE_IR_RAW_EVENT(ev);
+ int rc = 0;
+
+ if (!dev->raw)
+ return -EINVAL;
+
+ now = ktime_get();
+ delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
+
+ /* Check for a long duration since last event or if we're
+ * being called for the first time, note that delta can't
+ * possibly be negative.
+ */
+ if (delta > MS_TO_NS(500) || !dev->raw->last_type)
+ type |= IR_START_EVENT;
+ else
+ ev.duration = delta;
+
+ if (type & IR_START_EVENT)
+ ir_raw_event_reset(dev);
+ else if (dev->raw->last_type & IR_SPACE) {
+ ev.pulse = false;
+ rc = ir_raw_event_store(dev, &ev);
+ } else if (dev->raw->last_type & IR_PULSE) {
+ ev.pulse = true;
+ rc = ir_raw_event_store(dev, &ev);
+ } else
+ return 0;
+
+ dev->raw->last_event = now;
+ dev->raw->last_type = type;
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
+
+/**
+ * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing
+ * @dev: the struct rc_dev device descriptor
+ * @type: the type of the event that has occurred
+ *
+ * This routine (which may be called from an interrupt context) works
+ * in similar manner to ir_raw_event_store_edge.
+ * This routine is intended for devices with limited internal buffer
+ * It automerges samples of same type, and handles timeouts
+ */
+int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
+{
+ if (!dev->raw)
+ return -EINVAL;
+
+ /* Ignore spaces in idle mode */
+ if (dev->idle && !ev->pulse)
+ return 0;
+ else if (dev->idle)
+ ir_raw_event_set_idle(dev, false);
+
+ if (!dev->raw->this_ev.duration)
+ dev->raw->this_ev = *ev;
+ else if (ev->pulse == dev->raw->this_ev.pulse)
+ dev->raw->this_ev.duration += ev->duration;
+ else {
+ ir_raw_event_store(dev, &dev->raw->this_ev);
+ dev->raw->this_ev = *ev;
+ }
+
+ /* Enter idle mode if nessesary */
+ if (!ev->pulse && dev->timeout &&
+ dev->raw->this_ev.duration >= dev->timeout)
+ ir_raw_event_set_idle(dev, true);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
+
+/**
+ * ir_raw_event_set_idle() - provide hint to rc-core when the device is idle or not
+ * @dev: the struct rc_dev device descriptor
+ * @idle: whether the device is idle or not
+ */
+void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
+{
+ if (!dev->raw)
+ return;
+
+ IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
+
+ if (idle) {
+ dev->raw->this_ev.timeout = true;
+ ir_raw_event_store(dev, &dev->raw->this_ev);
+ init_ir_raw_event(&dev->raw->this_ev);
+ }
+
+ if (dev->s_idle)
+ dev->s_idle(dev, idle);
+
+ dev->idle = idle;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
+
+/**
+ * ir_raw_event_handle() - schedules the decoding of stored ir data
+ * @dev: the struct rc_dev device descriptor
+ *
+ * This routine will tell rc-core to start decoding stored ir data.
+ */
+void ir_raw_event_handle(struct rc_dev *dev)
+{
+ unsigned long flags;
+
+ if (!dev->raw)
+ return;
+
+ spin_lock_irqsave(&dev->raw->lock, flags);
+ wake_up_process(dev->raw->thread);
+ spin_unlock_irqrestore(&dev->raw->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_handle);
+
+/* used internally by the sysfs interface */
+static u64
+ir_raw_get_allowed_protocols(struct rc_dev *dev)
+{
+ u64 protocols;
+ mutex_lock(&ir_raw_handler_lock);
+ protocols = available_protocols;
+ mutex_unlock(&ir_raw_handler_lock);
+ return protocols;
+}
+
+/*
+ * Used to (un)register raw event clients
+ */
+int rc_register_ir_raw_device(struct rc_dev *dev)
+{
+ int rc;
+ struct ir_raw_handler *handler;
+
+ if (!dev)
+ return -EINVAL;
+
+ dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL);
+ if (!dev->raw)
+ return -ENOMEM;
+
+ dev->raw->dev = dev;
+ dev->enabled_protocols = ~0;
+ dev->get_protocols = ir_raw_get_allowed_protocols;
+ dev->driver_type = RC_DRIVER_IR_RAW;
+ spin_lock_init(&dev->raw->lock);
+ rc = kfifo_alloc(&dev->raw->kfifo,
+ sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
+ GFP_KERNEL);
+ if (rc < 0)
+ goto out;
+
+ dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
+ "rc-ir-raw-decode");
+ if (IS_ERR(dev->raw->thread)) {
+ rc = PTR_ERR(dev->raw->thread);
+ goto out;
+ }
+
+ rc = rc_register_device(dev);
+ if (rc < 0)
+ goto out_thread;
+
+ mutex_lock(&ir_raw_handler_lock);
+ list_add_tail(&dev->raw->list, &ir_raw_client_list);
+ list_for_each_entry(handler, &ir_raw_handler_list, list)
+ if (handler->raw_register)
+ handler->raw_register(dev);
+ mutex_unlock(&ir_raw_handler_lock);
+
+ return 0;
+
+out_thread:
+ kthread_stop(dev->raw->thread);
+out:
+ kfree(dev->raw);
+ dev->raw = NULL;
+ return rc;
+}
+EXPORT_SYMBOL_GPL(rc_register_ir_raw_device);
+
+void rc_unregister_ir_raw_device(struct rc_dev *dev)
+{
+ struct ir_raw_handler *handler;
+
+ if (!dev || !dev->raw)
+ return;
+
+ kthread_stop(dev->raw->thread);
+
+ mutex_lock(&ir_raw_handler_lock);
+ list_del(&dev->raw->list);
+ list_for_each_entry(handler, &ir_raw_handler_list, list)
+ if (handler->raw_unregister)
+ handler->raw_unregister(dev);
+ mutex_unlock(&ir_raw_handler_lock);
+
+ kfifo_free(&dev->raw->kfifo);
+ kfree(dev->raw);
+ dev->raw = NULL;
+ rc_unregister_device(dev);
+}
+EXPORT_SYMBOL_GPL(rc_unregister_ir_raw_device);
+
+/*
+ * Extension interface - used to register the IR decoders
+ */
+
+int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
+{
+ struct ir_raw_event_ctrl *raw;
+
+ mutex_lock(&ir_raw_handler_lock);
+ list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
+ if (ir_raw_handler->raw_register)
+ list_for_each_entry(raw, &ir_raw_client_list, list)
+ ir_raw_handler->raw_register(raw->dev);
+ available_protocols |= ir_raw_handler->protocols;
+ mutex_unlock(&ir_raw_handler_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(ir_raw_handler_register);
+
+void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
+{
+ struct ir_raw_event_ctrl *raw;
+
+ mutex_lock(&ir_raw_handler_lock);
+ list_del(&ir_raw_handler->list);
+ if (ir_raw_handler->raw_unregister)
+ list_for_each_entry(raw, &ir_raw_client_list, list)
+ ir_raw_handler->raw_unregister(raw->dev);
+ available_protocols &= ~ir_raw_handler->protocols;
+ mutex_unlock(&ir_raw_handler_lock);
+}
+EXPORT_SYMBOL(ir_raw_handler_unregister);
+
+static struct work_struct wq_load;
+
+static void rc_ir_raw_init_decoders(struct work_struct *work)
+{
+ /* Load the decoder modules */
+ load_nec_decode();
+ load_rc5_decode();
+ load_rc6_decode();
+ load_jvc_decode();
+ load_sony_decode();
+ load_sanyo_decode();
+ load_mce_kbd_decode();
+ load_lirc_codec();
+}
+
+static int __init rc_ir_raw_init(void)
+{
+ INIT_WORK(&wq_load, rc_ir_raw_init_decoders);
+ schedule_work(&wq_load);
+ return 0;
+}
+
+subsys_initcall(rc_ir_raw_init);
+
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index af64d15..7775b3e 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -26,7 +26,7 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/sched.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#define DRIVER_NAME "rc-loopback"
#define dprintk(x...) if (debug) printk(KERN_INFO DRIVER_NAME ": " x)
@@ -242,7 +242,7 @@ static int __init loop_init(void)
loopdev.learning = false;
loopdev.carrierreport = false;
- ret = rc_register_device(rc);
+ ret = rc_register_ir_raw_device(rc);
if (ret < 0) {
printk(KERN_ERR DRIVER_NAME ": rc_dev registration failed\n");
rc_free_device(rc);
@@ -255,7 +255,7 @@ static int __init loop_init(void)
static void __exit loop_exit(void)
{
- rc_unregister_device(loopdev.dev);
+ rc_unregister_ir_raw_device(loopdev.dev);
}
module_init(loop_init);
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 4edaffb..c2c42f9 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -249,10 +249,7 @@ static ssize_t show_protocols(struct device *device,
mutex_lock(&dev->lock);
enabled = dev->enabled_protocols;
- if (dev->driver_type == RC_DRIVER_SCANCODE)
- allowed = dev->allowed_protos;
- else
- allowed = ir_raw_get_allowed_protocols();
+ allowed = dev->get_protocols(dev);
IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
(long long)allowed,
@@ -536,9 +533,13 @@ static int rc_remove_keytable(struct rc_dev *dev, unsigned i)
return 0;
}
+static u64 rc_get_allowed_protocols(struct rc_dev *dev)
+{
+ return dev ? dev->allowed_protos : 0x0;
+}
+
int rc_register_device(struct rc_dev *dev)
{
- static bool raw_init = false; /* raw decoders loaded? */
const char *path;
int rc;
unsigned int i;
@@ -564,28 +565,19 @@ int rc_register_device(struct rc_dev *dev)
dev_set_name(&dev->dev, "rc%u", dev->minor);
dev_set_drvdata(&dev->dev, dev);
+ if (!dev->get_protocols)
+ dev->get_protocols = rc_get_allowed_protocols;
+
if (dev->tx_ir) {
rc = kfifo_alloc(&dev->txfifo, RC_TX_KFIFO_SIZE, GFP_KERNEL);
if (rc)
goto out;
}
- if (dev->driver_type == RC_DRIVER_IR_RAW) {
- /* Load raw decoders, if they aren't already */
- if (!raw_init) {
- IR_dprintk(1, "Loading raw decoders\n");
- ir_raw_init();
- raw_init = true;
- }
- rc = ir_raw_event_register(dev);
- if (rc < 0)
- goto out_kfifo;
- }
-
if (dev->change_protocol) {
rc = dev->change_protocol(dev, dev->enabled_protocols);
if (rc < 0)
- goto out_raw;
+ goto out_kfifo;
}
rc_dev_table[i] = dev;
@@ -615,9 +607,6 @@ out_device:
device_del(&dev->dev);
out_chardev:
rc_dev_table[dev->minor] = NULL;
-out_raw:
- if (dev->driver_type == RC_DRIVER_IR_RAW)
- ir_raw_event_unregister(dev);
out_kfifo:
kfifo_free(&dev->txfifo);
out:
@@ -651,9 +640,6 @@ void rc_unregister_device(struct rc_dev *dev)
wake_up_interruptible_all(&dev->rxwait);
wake_up_interruptible_all(&dev->txwait);
- if (dev->driver_type == RC_DRIVER_IR_RAW)
- ir_raw_event_unregister(dev);
-
device_unregister(&dev->dev);
}
@@ -914,10 +900,7 @@ void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx)
rx->rx_enabled = 0x1;
rx->rx_connected = 0x1;
rx->protocols_enabled[0] = dev->enabled_protocols;
- if (dev->driver_type == RC_DRIVER_SCANCODE)
- rx->protocols_supported[0] = dev->allowed_protos;
- else
- rx->protocols_supported[0] = ir_raw_get_allowed_protocols();
+ rx->protocols_supported[0] = dev->get_protocols(dev);
rx->timeout = dev->timeout;
rx->timeout_min = dev->min_timeout;
rx->timeout_max = dev->max_timeout;
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 5eefb0b..394799d 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -50,7 +50,7 @@
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb/input.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
/* Driver Information */
#define DRIVER_VERSION "0.70"
@@ -1037,7 +1037,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
rc->driver_name = DRIVER_NAME;
rc->map_name = RC_MAP_HAUPPAUGE;
- ret = rc_register_device(rc);
+ ret = rc_register_ir_raw_device(rc);
if (ret < 0) {
dev_err(dev, "remote dev registration failed\n");
goto out;
@@ -1201,7 +1201,7 @@ static void __devexit redrat3_dev_disconnect(struct usb_interface *intf)
redrat3_disable_detector(rr3);
usb_set_intfdata(intf, NULL);
- rc_unregister_device(rr3->rc);
+ rc_unregister_ir_raw_device(rr3->rc);
del_timer_sync(&rr3->rx_timeout);
redrat3_delete(rr3, udev);
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index fdfedc6..4156197 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -36,7 +36,7 @@
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb/input.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#define DRIVER_VERSION "1.61"
#define DRIVER_NAME "streamzap"
@@ -319,7 +319,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
rdev->driver_name = DRIVER_NAME;
rdev->map_name = RC_MAP_STREAMZAP;
- ret = rc_register_device(rdev);
+ ret = rc_register_ir_raw_device(rdev);
if (ret < 0) {
dev_err(dev, "remote input device register failed\n");
goto out;
@@ -484,7 +484,7 @@ static void streamzap_disconnect(struct usb_interface *interface)
return;
sz->usbdev = NULL;
- rc_unregister_device(sz->rdev);
+ rc_unregister_ir_raw_device(sz->rdev);
usb_kill_urb(sz->urb_in);
usb_free_urb(sz->urb_in);
usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in);
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 207410c..5a240ba 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -55,7 +55,7 @@
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/sched.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#define DRVNAME "winbond-cir"
@@ -1056,7 +1056,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
goto exit_release_sbase;
}
- err = rc_register_device(data->dev);
+ err = rc_register_ir_raw_device(data->dev);
if (err)
goto exit_free_irq;
@@ -1107,7 +1107,7 @@ wbcir_remove(struct pnp_dev *device)
/* Clear BUFF_EN, END_EN, MATCH_EN */
wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
- rc_unregister_device(data->dev);
+ rc_unregister_ir_raw_device(data->dev);
led_trigger_unregister_simple(data->rxtrigger);
led_trigger_unregister_simple(data->txtrigger);
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index b391e9b..5931e3f 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -6,7 +6,7 @@ config VIDEO_CX23885
select VIDEO_BTCX
select VIDEO_TUNER
select VIDEO_TVEEPROM
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
select VIDEOBUF_DVB
select VIDEOBUF_DMA_SG
select VIDEO_CX25840
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
index 6aa96a2..dbf0d34 100644
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -36,7 +36,7 @@
*/
#include <linux/slab.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#include <media/v4l2-subdev.h>
#include "cx23885.h"
@@ -324,7 +324,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
/* Go */
dev->kernel_ir = kernel_ir;
- ret = rc_register_device(rc);
+ ret = rc_register_ir_raw_device(rc);
if (ret)
goto err_out_stop;
@@ -348,7 +348,7 @@ void cx23885_input_fini(struct cx23885_dev *dev)
if (dev->kernel_ir == NULL)
return;
- rc_unregister_device(dev->kernel_ir->rc);
+ rc_unregister_ir_raw_device(dev->kernel_ir->rc);
kfree(dev->kernel_ir->phys);
kfree(dev->kernel_ir->name);
kfree(dev->kernel_ir);
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c
index c2bc39c..f3609a2 100644
--- a/drivers/media/video/cx23885/cx23888-ir.c
+++ b/drivers/media/video/cx23885/cx23888-ir.c
@@ -26,7 +26,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#include "cx23885.h"
diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/video/cx25840/cx25840-ir.c
index 38ce76e..cd3aca7 100644
--- a/drivers/media/video/cx25840/cx25840-ir.c
+++ b/drivers/media/video/cx25840/cx25840-ir.c
@@ -25,7 +25,7 @@
#include <linux/kfifo.h>
#include <linux/module.h>
#include <media/cx25840.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#include "cx25840-core.h"
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 3598dc0..63f2351 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_CX88
tristate "Conexant 2388x (bt878 successor) support"
- depends on VIDEO_DEV && PCI && I2C && RC_CORE
+ depends on VIDEO_DEV && PCI && I2C && RC_CORE && RC_IR_RAW
select I2C_ALGOBIT
select VIDEO_BTCX
select VIDEOBUF_DMA_SG
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 2962ef7..158c1b6 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -29,7 +29,7 @@
#include <linux/module.h>
#include "cx88.h"
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#define MODULE_NAME "cx88xx"
@@ -473,7 +473,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
core->ir = ir;
/* all done */
- err = rc_register_device(dev);
+ err = rc_register_ir_raw_device(dev);
if (err)
goto err_out_free;
@@ -495,7 +495,7 @@ int cx88_ir_fini(struct cx88_core *core)
return 0;
cx88_ir_stop(core);
- rc_unregister_device(ir->dev);
+ rc_unregister_ir_raw_device(ir->dev);
kfree(ir);
/* done */
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 39fc018..2b1596f 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -26,7 +26,7 @@ config VIDEO_SAA7134_ALSA
config VIDEO_SAA7134_RC
bool "Philips SAA7134 Remote Controller support"
- depends on RC_CORE
+ depends on RC_CORE && RC_IR_RAW
depends on VIDEO_SAA7134
depends on !(RC_CORE=m && VIDEO_SAA7134=y)
default y
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 6b5fc7f..9b54082 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -873,7 +873,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
rc->map_name = ir_codes;
rc->driver_name = MODULE_NAME;
- err = rc_register_device(rc);
+ err = rc_register_ir_raw_device(rc);
if (err)
goto err_out_free;
@@ -892,7 +892,7 @@ void saa7134_input_fini(struct saa7134_dev *dev)
return;
saa7134_ir_stop(dev);
- rc_unregister_device(dev->remote->dev);
+ rc_unregister_ir_raw_device(dev->remote->dev);
kfree(dev->remote);
dev->remote = NULL;
}
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 89c8333..56edbf7 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -36,7 +36,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
#include <media/tuner.h>
-#include <media/rc-core.h>
+#include <media/rc-ir-raw.h>
#include <media/ir-kbd-i2c.h>
#include <media/videobuf-dma-sg.h>
#include <sound/core.h>
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 1a38ecc..cf66e91 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -258,6 +258,7 @@ struct ir_raw_event {
* @max_timeout: maximum timeout supported by device
* @rx_resolution : resolution (in ns) of input sampler
* @tx_resolution: resolution (in ns) of output sampler
+ * @get_protocols: returns a bitmask of allowed protocols
* @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.
@@ -309,6 +310,7 @@ struct rc_dev {
u32 max_timeout;
u32 rx_resolution;
u32 tx_resolution;
+ u64 (*get_protocols)(struct rc_dev *dev);
int (*change_protocol)(struct rc_dev *dev, u64 rc_type);
int (*open)(struct rc_dev *dev);
void (*close)(struct rc_dev *dev);
@@ -420,53 +422,6 @@ void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol, u64 scancode, u8 t
#define rc_keydown_notimeout(dev, proto, scan, toggle) rc_do_keydown(dev, proto, scan, toggle, false)
u32 rc_g_keycode_from_table(struct rc_dev *dev, enum rc_type protocol, u64 scancode);
-/*
- * From rc-raw.c
- * The Raw interface is specific to InfraRed. It may be a good idea to
- * split it later into a separate header.
- */
-
-enum raw_event_type {
- IR_SPACE = (1 << 0),
- IR_PULSE = (1 << 1),
- IR_START_EVENT = (1 << 2),
- IR_STOP_EVENT = (1 << 3),
-};
-
-#define DEFINE_IR_RAW_EVENT(event) \
- struct ir_raw_event event = { \
- { .duration = 0 } , \
- .pulse = 0, \
- .reset = 0, \
- .timeout = 0, \
- .carrier_report = 0 }
-
-static inline void init_ir_raw_event(struct ir_raw_event *ev)
-{
- memset(ev, 0, sizeof(*ev));
-}
-
-#define IR_MAX_DURATION 0xFFFFFFFF /* a bit more than 4 seconds */
-#define US_TO_NS(usec) ((usec) * 1000)
-#define MS_TO_US(msec) ((msec) * 1000)
-#define MS_TO_NS(msec) ((msec) * 1000 * 1000)
-
-void ir_raw_event_handle(struct rc_dev *dev);
-int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
-int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
-int ir_raw_event_store_with_filter(struct rc_dev *dev,
- struct ir_raw_event *ev);
-void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
-
-static inline void ir_raw_event_reset(struct rc_dev *dev)
-{
- DEFINE_IR_RAW_EVENT(ev);
- ev.reset = true;
-
- ir_raw_event_store(dev, &ev);
- ir_raw_event_handle(dev);
-}
-
/* extract mask bits out of data and pack them into the result */
static inline u32 ir_extract_bits(u32 data, u32 mask)
{
diff --git a/include/media/rc-ir-raw.h b/include/media/rc-ir-raw.h
new file mode 100644
index 0000000..4c3fe78
--- /dev/null
+++ b/include/media/rc-ir-raw.h
@@ -0,0 +1,68 @@
+/*
+ * Remote Controller IR raw decoding header
+ *
+ * Copyright (C) 2009-2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _RC_IR_RAW
+#define _RC_IR_RAW
+
+#include <linux/spinlock.h>
+#include <linux/kfifo.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <media/rc-core.h>
+
+enum raw_event_type {
+ IR_SPACE = (1 << 0),
+ IR_PULSE = (1 << 1),
+ IR_START_EVENT = (1 << 2),
+ IR_STOP_EVENT = (1 << 3),
+};
+
+#define DEFINE_IR_RAW_EVENT(event) \
+ struct ir_raw_event event = { \
+ { .duration = 0 } , \
+ .pulse = 0, \
+ .reset = 0, \
+ .timeout = 0, \
+ .carrier_report = 0 }
+
+static inline void init_ir_raw_event(struct ir_raw_event *ev)
+{
+ memset(ev, 0, sizeof(*ev));
+}
+
+#define IR_MAX_DURATION 0xFFFFFFFF /* a bit more than 4 seconds */
+#define US_TO_NS(usec) ((usec) * 1000)
+#define MS_TO_US(msec) ((msec) * 1000)
+#define MS_TO_NS(msec) ((msec) * 1000 * 1000)
+
+void ir_raw_event_handle(struct rc_dev *dev);
+int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
+int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
+int ir_raw_event_store_with_filter(struct rc_dev *dev,
+ struct ir_raw_event *ev);
+void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
+int rc_register_ir_raw_device(struct rc_dev *dev);
+void rc_unregister_ir_raw_device(struct rc_dev *dev);
+
+static inline void ir_raw_event_reset(struct rc_dev *dev)
+{
+ DEFINE_IR_RAW_EVENT(ev);
+ ev.reset = true;
+
+ ir_raw_event_store(dev, &ev);
+ ir_raw_event_handle(dev);
+}
+
+#endif /* _RC_IR_RAW */
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 33/43] rc-ir-raw: simplify locking
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (31 preceding siblings ...)
2012-05-23 9:44 ` [PATCH 32/43] rc-core: split IR raw handling to a separate module David Härdeman
@ 2012-05-23 9:44 ` David Härdeman
2012-05-23 9:44 ` [PATCH 34/43] rc-core: rename mutex David Härdeman
` (10 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:44 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Simplify and improve the locking in rc-ir-raw by making better use of
the existing kfifo functionality and by using RCU where possible.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-core-priv.h | 6 +-
drivers/media/rc/rc-ir-raw.c | 119 ++++++++++++++++-----------------------
2 files changed, 52 insertions(+), 73 deletions(-)
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index b2a5d99..b0e1686 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -33,11 +33,13 @@ struct ir_raw_handler {
int (*raw_unregister)(struct rc_dev *dev);
};
+/* max number of pulse/space transitions to buffer */
+#define RC_MAX_IR_EVENTS 512
+
struct ir_raw_event_ctrl {
struct list_head list; /* to keep track of raw clients */
struct task_struct *thread;
- spinlock_t lock;
- struct kfifo_rec_ptr_1 kfifo; /* fifo for the pulse/space durations */
+ DECLARE_KFIFO(kfifo, struct ir_raw_event, RC_MAX_IR_EVENTS); /* for pulse/space durations */
ktime_t last_event; /* when last event occurred */
enum raw_event_type last_type; /* last event type */
struct rc_dev *dev; /* pointer to the parent rc_dev */
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index a0d3508..42769b4 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -23,15 +23,12 @@
#include "rc-core-priv.h"
-/* Define the max number of pulse/space transitions to buffer */
-#define MAX_IR_EVENT_SIZE 512
-
-/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
+/* IR raw clients/handlers, writers synchronize with ir_raw_mutex */
+static DEFINE_MUTEX(ir_raw_mutex);
static LIST_HEAD(ir_raw_client_list);
-
-/* Used to handle IR raw handler extensions */
-static DEFINE_MUTEX(ir_raw_handler_lock);
static LIST_HEAD(ir_raw_handler_list);
+
+/* protocols supported by the currently loaded decoders */
static u64 available_protocols;
static int ir_raw_event_thread(void *data)
@@ -39,32 +36,19 @@ static int ir_raw_event_thread(void *data)
struct ir_raw_event ev;
struct ir_raw_handler *handler;
struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
- int retval;
while (!kthread_should_stop()) {
-
- spin_lock_irq(&raw->lock);
- retval = kfifo_len(&raw->kfifo);
-
- if (retval < sizeof(ev)) {
+ if (kfifo_out(&raw->kfifo, &ev, 1) == 0) {
set_current_state(TASK_INTERRUPTIBLE);
-
- if (kthread_should_stop())
- set_current_state(TASK_RUNNING);
-
- spin_unlock_irq(&raw->lock);
schedule();
continue;
}
- retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
- spin_unlock_irq(&raw->lock);
-
- mutex_lock(&ir_raw_handler_lock);
- list_for_each_entry(handler, &ir_raw_handler_list, list)
+ rcu_read_lock();
+ list_for_each_entry_rcu(handler, &ir_raw_handler_list, list)
handler->decode(raw->dev, ev);
+ rcu_read_unlock();
raw->prev_ev = ev;
- mutex_unlock(&ir_raw_handler_lock);
}
return 0;
@@ -78,7 +62,8 @@ static int ir_raw_event_thread(void *data)
* This routine (which may be called from an interrupt context) stores a
* pulse/space duration for the raw ir decoding state machines. Pulses are
* signalled as positive values and spaces as negative values. A zero value
- * will reset the decoding state machines.
+ * will reset the decoding state machines. Drivers are responsible for
+ * synchronizing calls to this function.
*/
int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
{
@@ -88,7 +73,7 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
IR_dprintk(2, "sample: (%05dus %s)\n",
TO_US(ev->duration), TO_STR(ev->pulse));
- if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
+ if (kfifo_in(&dev->raw->kfifo, ev, 1) != 1)
return -ENOMEM;
return 0;
@@ -217,14 +202,8 @@ EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
*/
void ir_raw_event_handle(struct rc_dev *dev)
{
- unsigned long flags;
-
- if (!dev->raw)
- return;
-
- spin_lock_irqsave(&dev->raw->lock, flags);
- wake_up_process(dev->raw->thread);
- spin_unlock_irqrestore(&dev->raw->lock, flags);
+ if (dev->raw)
+ wake_up_process(dev->raw->thread);
}
EXPORT_SYMBOL_GPL(ir_raw_event_handle);
@@ -233,9 +212,9 @@ static u64
ir_raw_get_allowed_protocols(struct rc_dev *dev)
{
u64 protocols;
- mutex_lock(&ir_raw_handler_lock);
+ mutex_lock(&ir_raw_mutex);
protocols = available_protocols;
- mutex_unlock(&ir_raw_handler_lock);
+ mutex_unlock(&ir_raw_mutex);
return protocols;
}
@@ -245,50 +224,46 @@ ir_raw_get_allowed_protocols(struct rc_dev *dev)
int rc_register_ir_raw_device(struct rc_dev *dev)
{
int rc;
+ struct ir_raw_event_ctrl *raw;
struct ir_raw_handler *handler;
if (!dev)
return -EINVAL;
- dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL);
- if (!dev->raw)
+ raw = kzalloc(sizeof(*raw), GFP_KERNEL);
+ if (!raw)
return -ENOMEM;
- dev->raw->dev = dev;
- dev->enabled_protocols = ~0;
- dev->get_protocols = ir_raw_get_allowed_protocols;
- dev->driver_type = RC_DRIVER_IR_RAW;
- spin_lock_init(&dev->raw->lock);
- rc = kfifo_alloc(&dev->raw->kfifo,
- sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
- GFP_KERNEL);
- if (rc < 0)
- goto out;
-
- dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
- "rc-ir-raw-decode");
- if (IS_ERR(dev->raw->thread)) {
- rc = PTR_ERR(dev->raw->thread);
+ raw->dev = dev;
+ INIT_KFIFO(raw->kfifo);
+ raw->thread = kthread_run(ir_raw_event_thread, raw, "rc-ir-raw-decode");
+ if (IS_ERR(raw->thread)) {
+ rc = PTR_ERR(raw->thread);
goto out;
}
+ dev->raw = raw;
+ dev->enabled_protocols = ~0;
+ dev->get_protocols = ir_raw_get_allowed_protocols;
+ dev->driver_type = RC_DRIVER_IR_RAW;
rc = rc_register_device(dev);
if (rc < 0)
goto out_thread;
- mutex_lock(&ir_raw_handler_lock);
- list_add_tail(&dev->raw->list, &ir_raw_client_list);
- list_for_each_entry(handler, &ir_raw_handler_list, list)
+ mutex_lock(&ir_raw_mutex);
+ list_add_tail_rcu(&dev->raw->list, &ir_raw_client_list);
+ list_for_each_entry_rcu(handler, &ir_raw_handler_list, list)
if (handler->raw_register)
handler->raw_register(dev);
- mutex_unlock(&ir_raw_handler_lock);
+ mutex_unlock(&ir_raw_mutex);
+ synchronize_rcu();
return 0;
out_thread:
kthread_stop(dev->raw->thread);
out:
- kfree(dev->raw);
+ kfree(raw);
dev->raw = NULL;
return rc;
}
@@ -303,14 +278,14 @@ void rc_unregister_ir_raw_device(struct rc_dev *dev)
kthread_stop(dev->raw->thread);
- mutex_lock(&ir_raw_handler_lock);
- list_del(&dev->raw->list);
- list_for_each_entry(handler, &ir_raw_handler_list, list)
+ mutex_lock(&ir_raw_mutex);
+ list_del_rcu(&dev->raw->list);
+ list_for_each_entry_rcu(handler, &ir_raw_handler_list, list)
if (handler->raw_unregister)
handler->raw_unregister(dev);
- mutex_unlock(&ir_raw_handler_lock);
+ mutex_unlock(&ir_raw_mutex);
+ synchronize_rcu();
- kfifo_free(&dev->raw->kfifo);
kfree(dev->raw);
dev->raw = NULL;
rc_unregister_device(dev);
@@ -325,13 +300,14 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
{
struct ir_raw_event_ctrl *raw;
- mutex_lock(&ir_raw_handler_lock);
- list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
+ mutex_lock(&ir_raw_mutex);
+ list_add_tail_rcu(&ir_raw_handler->list, &ir_raw_handler_list);
if (ir_raw_handler->raw_register)
- list_for_each_entry(raw, &ir_raw_client_list, list)
+ list_for_each_entry_rcu(raw, &ir_raw_client_list, list)
ir_raw_handler->raw_register(raw->dev);
available_protocols |= ir_raw_handler->protocols;
- mutex_unlock(&ir_raw_handler_lock);
+ mutex_unlock(&ir_raw_mutex);
+ synchronize_rcu();
return 0;
}
@@ -341,13 +317,14 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
{
struct ir_raw_event_ctrl *raw;
- mutex_lock(&ir_raw_handler_lock);
- list_del(&ir_raw_handler->list);
+ mutex_lock(&ir_raw_mutex);
+ list_del_rcu(&ir_raw_handler->list);
if (ir_raw_handler->raw_unregister)
- list_for_each_entry(raw, &ir_raw_client_list, list)
+ list_for_each_entry_rcu(raw, &ir_raw_client_list, list)
ir_raw_handler->raw_unregister(raw->dev);
available_protocols &= ~ir_raw_handler->protocols;
- mutex_unlock(&ir_raw_handler_lock);
+ mutex_unlock(&ir_raw_mutex);
+ synchronize_rcu();
}
EXPORT_SYMBOL(ir_raw_handler_unregister);
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 34/43] rc-core: rename mutex
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (32 preceding siblings ...)
2012-05-23 9:44 ` [PATCH 33/43] rc-ir-raw: simplify locking David Härdeman
@ 2012-05-23 9:44 ` David Härdeman
2012-05-23 9:45 ` [PATCH 35/43] rc-ir-raw: atomic reads of protocols David Härdeman
` (9 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:44 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Having a mutex named "lock" is a bit misleading.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-keytable.c | 8 ++++----
drivers/media/rc/rc-main.c | 22 +++++++++++-----------
include/media/rc-core.h | 4 ++--
3 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index d5b1d88..84c6e96 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -699,14 +699,14 @@ static int rc_input_open(struct input_dev *idev)
struct rc_keytable *kt = input_get_drvdata(idev);
struct rc_dev *dev = kt->dev;
- error = mutex_lock_interruptible(&dev->lock);
+ error = mutex_lock_interruptible(&dev->mutex);
if (error)
return error;
if (dev->users++ == 0 && dev->open)
error = dev->open(dev);
- mutex_unlock(&dev->lock);
+ mutex_unlock(&dev->mutex);
return error;
}
@@ -722,12 +722,12 @@ static void rc_input_close(struct input_dev *idev)
struct rc_keytable *kt = input_get_drvdata(idev);
struct rc_dev *dev = kt->dev;
- mutex_lock(&dev->lock);
+ mutex_lock(&dev->mutex);
if (--dev->users == 0 && dev->close)
dev->close(dev);
- mutex_unlock(&dev->lock);
+ mutex_unlock(&dev->mutex);
}
/**
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index c2c42f9..14728fc 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -231,7 +231,7 @@ static struct {
* It returns the protocol names of supported protocols.
* Enabled protocols are printed in brackets.
*
- * dev->lock is taken to guard against races between store_protocols
+ * dev->mutex is taken to guard against races between store_protocols
* and show_protocols.
*/
static ssize_t show_protocols(struct device *device,
@@ -246,7 +246,7 @@ static ssize_t show_protocols(struct device *device,
if (!dev)
return -EINVAL;
- mutex_lock(&dev->lock);
+ mutex_lock(&dev->mutex);
enabled = dev->enabled_protocols;
allowed = dev->get_protocols(dev);
@@ -269,7 +269,7 @@ static ssize_t show_protocols(struct device *device,
tmp--;
*tmp = '\n';
- mutex_unlock(&dev->lock);
+ mutex_unlock(&dev->mutex);
return tmp + 1 - buf;
}
@@ -290,7 +290,7 @@ static ssize_t show_protocols(struct device *device,
* Returns -EINVAL if an invalid protocol combination or unknown protocol name
* is used, otherwise @len.
*
- * dev->lock is taken to guard against races between store_protocols and
+ * dev->mutex is taken to guard against races between store_protocols and
* show_protocols.
*/
static ssize_t store_protocols(struct device *device,
@@ -310,7 +310,7 @@ static ssize_t store_protocols(struct device *device,
if (!dev)
return -EINVAL;
- mutex_lock(&dev->lock);
+ mutex_lock(&dev->mutex);
if (dev->driver_type != RC_DRIVER_SCANCODE && !dev->raw) {
IR_dprintk(1, "Protocol switching not supported\n");
@@ -383,7 +383,7 @@ static ssize_t store_protocols(struct device *device,
ret = len;
out:
- mutex_unlock(&dev->lock);
+ mutex_unlock(&dev->mutex);
return ret;
}
@@ -467,7 +467,7 @@ struct rc_dev *rc_allocate_device(void)
init_waitqueue_head(&dev->rxwait);
init_waitqueue_head(&dev->txwait);
spin_lock_init(&dev->txlock);
- mutex_init(&dev->lock);
+ mutex_init(&dev->mutex);
dev->dev.type = &rc_dev_type;
dev->dev.class = &rc_class;
@@ -623,11 +623,11 @@ void rc_unregister_device(struct rc_dev *dev)
if (!dev)
return;
- mutex_lock(&dev->lock);
+ mutex_lock(&dev->mutex);
dev->exist = false;
for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
rc_remove_keytable(dev, i);
- mutex_unlock(&dev->lock);
+ mutex_unlock(&dev->mutex);
mutex_lock(&rc_dev_table_mutex);
rc_dev_table[dev->minor] = NULL;
@@ -1071,7 +1071,7 @@ static long rc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct rc_dev *dev = client->dev;
int ret;
- ret = mutex_lock_interruptible(&dev->lock);
+ ret = mutex_lock_interruptible(&dev->mutex);
if (ret)
return ret;
@@ -1083,7 +1083,7 @@ static long rc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret = rc_do_ioctl(dev, cmd, arg);
out:
- mutex_unlock(&dev->lock);
+ mutex_unlock(&dev->mutex);
return ret;
}
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index cf66e91..ab9a72e 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -226,7 +226,7 @@ struct ir_raw_event {
* @driver_name: name of the hardware driver which registered this device
* @map_name: name of the default keymap
* @rc_map: current scan/key table
- * @lock: used where a more specific lock/mutex/etc is not available
+ * @mutex: used where a more specific lock/mutex/etc is not available
* @minor: unique minor remote control device number
* @exist: used to determine if the device is still valid
* @client_list: list of clients (processes which have opened the rc chardev)
@@ -288,7 +288,7 @@ struct rc_dev {
const char *map_name;
struct rc_keytable *keytables[RC_MAX_KEYTABLES];
struct list_head keytable_list;
- struct mutex lock;
+ struct mutex mutex;
unsigned int minor;
bool exist;
struct list_head client_list;
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 35/43] rc-ir-raw: atomic reads of protocols
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (33 preceding siblings ...)
2012-05-23 9:44 ` [PATCH 34/43] rc-core: rename mutex David Härdeman
@ 2012-05-23 9:45 ` David Härdeman
2012-05-23 9:45 ` [PATCH 36/43] rc-core: fix various sparse warnings David Härdeman
` (8 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:45 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Use atomic reads to avoid having to take a mutex when getting
the bitmask of supported protocols.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-core-priv.h | 2 +-
drivers/media/rc/rc-ir-raw.c | 12 ++++--------
2 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index b0e1686..54af19a 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -25,7 +25,7 @@
struct ir_raw_handler {
struct list_head list;
- u64 protocols; /* which are handled by this handler */
+ unsigned protocols; /* which are handled by this handler */
int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
/* These two should only be used by the lirc decoder */
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 42769b4..88a2932 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -29,7 +29,7 @@ static LIST_HEAD(ir_raw_client_list);
static LIST_HEAD(ir_raw_handler_list);
/* protocols supported by the currently loaded decoders */
-static u64 available_protocols;
+static atomic_t available_protocols = ATOMIC_INIT(0);
static int ir_raw_event_thread(void *data)
{
@@ -211,11 +211,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_handle);
static u64
ir_raw_get_allowed_protocols(struct rc_dev *dev)
{
- u64 protocols;
- mutex_lock(&ir_raw_mutex);
- protocols = available_protocols;
- mutex_unlock(&ir_raw_mutex);
- return protocols;
+ return atomic_read(&available_protocols);
}
/*
@@ -305,7 +301,7 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
if (ir_raw_handler->raw_register)
list_for_each_entry_rcu(raw, &ir_raw_client_list, list)
ir_raw_handler->raw_register(raw->dev);
- available_protocols |= ir_raw_handler->protocols;
+ atomic_set_mask(ir_raw_handler->protocols, &available_protocols);
mutex_unlock(&ir_raw_mutex);
synchronize_rcu();
@@ -322,7 +318,7 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
if (ir_raw_handler->raw_unregister)
list_for_each_entry_rcu(raw, &ir_raw_client_list, list)
ir_raw_handler->raw_unregister(raw->dev);
- available_protocols &= ~ir_raw_handler->protocols;
+ atomic_clear_mask(ir_raw_handler->protocols, &available_protocols);
mutex_unlock(&ir_raw_mutex);
synchronize_rcu();
}
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 36/43] rc-core: fix various sparse warnings
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (34 preceding siblings ...)
2012-05-23 9:45 ` [PATCH 35/43] rc-ir-raw: atomic reads of protocols David Härdeman
@ 2012-05-23 9:45 ` David Härdeman
2012-05-23 9:45 ` [PATCH 37/43] rc-core: don't report scancodes via input devices David Härdeman
` (7 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:45 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Fix various sparse warnings under drivers/media/rc/*.c, mostly
by making functions static.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/ene_ir.c | 2 +-
drivers/media/rc/fintek-cir.c | 4 ++--
drivers/media/rc/imon.c | 8 ++++----
drivers/media/rc/ite-cir.c | 4 ++--
drivers/media/rc/nuvoton-cir.c | 4 ++--
5 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index eb107e8..2c2cfd5 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -329,7 +329,7 @@ static int ene_rx_get_sample_reg(struct ene_device *dev)
}
/* Sense current received carrier */
-void ene_rx_sense_carrier(struct ene_device *dev)
+static void ene_rx_sense_carrier(struct ene_device *dev)
{
DEFINE_IR_RAW_EVENT(ev);
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index 01e6ef8..ac949ae 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -675,12 +675,12 @@ static struct pnp_driver fintek_driver = {
.shutdown = fintek_shutdown,
};
-int fintek_init(void)
+static int __init fintek_init(void)
{
return pnp_register_driver(&fintek_driver);
}
-void fintek_exit(void)
+static void __exit fintek_exit(void)
{
pnp_unregister_driver(&fintek_driver);
}
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index d98778b..8573977 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -78,11 +78,11 @@ static int display_open(struct inode *inode, struct file *file);
static int display_close(struct inode *inode, struct file *file);
/* VFD write operation */
-static ssize_t vfd_write(struct file *file, const char *buf,
+static ssize_t vfd_write(struct file *file, const char __user *buf,
size_t n_bytes, loff_t *pos);
/* LCD file_operations override function prototypes */
-static ssize_t lcd_write(struct file *file, const char *buf,
+static ssize_t lcd_write(struct file *file, const char __user *buf,
size_t n_bytes, loff_t *pos);
/*** G L O B A L S ***/
@@ -818,7 +818,7 @@ static struct attribute_group imon_rf_attr_group = {
* than 32 bytes are provided spaces will be appended to
* generate a full screen.
*/
-static ssize_t vfd_write(struct file *file, const char *buf,
+static ssize_t vfd_write(struct file *file, const char __user *buf,
size_t n_bytes, loff_t *pos)
{
int i;
@@ -905,7 +905,7 @@ exit:
* display whatever diacritics you need, and so on), but it's also
* a lot more complicated than most LCDs...
*/
-static ssize_t lcd_write(struct file *file, const char *buf,
+static ssize_t lcd_write(struct file *file, const char __user *buf,
size_t n_bytes, loff_t *pos)
{
int retval = 0;
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 6721767..44759db 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1705,12 +1705,12 @@ static struct pnp_driver ite_driver = {
.shutdown = ite_shutdown,
};
-int ite_init(void)
+static int __init ite_init(void)
{
return pnp_register_driver(&ite_driver);
}
-void ite_exit(void)
+static void __exit ite_exit(void)
{
pnp_unregister_driver(&ite_driver);
}
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 0548db4..915074e 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -1223,12 +1223,12 @@ static struct pnp_driver nvt_driver = {
.shutdown = nvt_shutdown,
};
-int nvt_init(void)
+static int __init nvt_init(void)
{
return pnp_register_driver(&nvt_driver);
}
-void nvt_exit(void)
+static void __exit nvt_exit(void)
{
pnp_unregister_driver(&nvt_driver);
}
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 37/43] rc-core: don't report scancodes via input devices
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (35 preceding siblings ...)
2012-05-23 9:45 ` [PATCH 36/43] rc-core: fix various sparse warnings David Härdeman
@ 2012-05-23 9:45 ` David Härdeman
2012-05-23 9:45 ` [PATCH 38/43] rc-ir-raw: add various rc_events David Härdeman
` (6 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:45 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
The scancode that is reported via the input device(s) is now incomplete
(missing the protocol) and redundant.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-keytable.c | 21 +++++----------------
1 file changed, 5 insertions(+), 16 deletions(-)
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index 84c6e96..d0777cb 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -611,17 +611,10 @@ void rc_keytable_repeat(struct rc_keytable *kt)
unsigned long flags;
spin_lock_irqsave(&kt->key_lock, flags);
-
- input_event(kt->idev, EV_MSC, MSC_SCAN, kt->last_scancode);
- input_sync(kt->idev);
-
- if (!kt->key_pressed)
- goto out;
-
- kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
- mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
-
-out:
+ if (kt->key_pressed) {
+ kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
+ mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
+ }
spin_unlock_irqrestore(&kt->key_lock, flags);
}
@@ -660,8 +653,6 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
if (new_event)
rc_do_keyup(kt, false);
- input_event(kt->idev, EV_MSC, MSC_SCAN, scancode);
-
if (new_event && keycode != KEY_RESERVED) {
/* Register a keypress */
kt->key_pressed = true;
@@ -675,8 +666,8 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
kt->dev->input_name, keycode, protocol,
(long long unsigned)scancode);
input_report_key(kt->idev, keycode, 1);
+ input_sync(kt->idev);
}
- input_sync(kt->idev);
if (autoup && kt->key_pressed) {
kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
@@ -799,8 +790,6 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev,
idev->close = rc_input_close;
set_bit(EV_KEY, idev->evbit);
set_bit(EV_REP, idev->evbit);
- set_bit(EV_MSC, idev->evbit);
- set_bit(MSC_SCAN, idev->mscbit);
input_set_drvdata(idev, kt);
setup_timer(&kt->timer_keyup, rc_timer_keyup, (unsigned long)kt);
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 38/43] rc-ir-raw: add various rc_events
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (36 preceding siblings ...)
2012-05-23 9:45 ` [PATCH 37/43] rc-core: don't report scancodes via input devices David Härdeman
@ 2012-05-23 9:45 ` David Härdeman
2012-05-23 9:45 ` [PATCH 39/43] rc-core: use struct rc_event to signal TX events from userspace David Härdeman
` (5 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:45 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Reporting pulse/space events via the /dev/rc/rcX device node is an
important step towards having feature parity with LIRC.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-ir-raw.c | 11 +++++++++++
include/media/rc-core.h | 10 ++++++++++
2 files changed, 21 insertions(+)
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 88a2932..e6a6eea 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -73,6 +73,17 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
IR_dprintk(2, "sample: (%05dus %s)\n",
TO_US(ev->duration), TO_STR(ev->pulse));
+ if (ev->reset)
+ rc_event(dev, RC_IR_RAW, RC_IR_RAW_RESET, 1);
+ else if (ev->carrier_report)
+ rc_event(dev, RC_IR_RAW, RC_IR_RAW_CARRIER, ev->carrier);
+ else if (ev->timeout)
+ rc_event(dev, RC_IR_RAW, RC_IR_RAW_STOP, 1);
+ else if (ev->pulse)
+ rc_event(dev, RC_IR_RAW, RC_IR_RAW_PULSE, ev->duration);
+ else
+ rc_event(dev, RC_IR_RAW, RC_IR_RAW_SPACE, ev->duration);
+
if (kfifo_in(&dev->raw->kfifo, ev, 1) != 1)
return -ENOMEM;
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index ab9a72e..f2ff7f7 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -378,6 +378,7 @@ struct rc_keytable {
#define RC_DEBUG 0x0
#define RC_CORE 0x1
#define RC_KEY 0x2
+#define RC_IR_RAW 0x3
/* RC_CORE codes */
#define RC_CORE_DROPPED 0x0
@@ -388,6 +389,15 @@ struct rc_keytable {
#define RC_KEY_SCANCODE 0x2
#define RC_KEY_TOGGLE 0x3
+/* RC_IR_RAW codes */
+#define RC_IR_RAW_SPACE 0x0
+#define RC_IR_RAW_PULSE 0x1
+#define RC_IR_RAW_START 0x2
+#define RC_IR_RAW_STOP 0x3
+#define RC_IR_RAW_RESET 0x4
+#define RC_IR_RAW_CARRIER 0x5
+#define RC_IR_RAW_DUTY_CYCLE 0x6
+
/**
* struct rc_event - used to communicate rc events to userspace
* @type: the event type
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 39/43] rc-core: use struct rc_event to signal TX events from userspace
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (37 preceding siblings ...)
2012-05-23 9:45 ` [PATCH 38/43] rc-ir-raw: add various rc_events David Härdeman
@ 2012-05-23 9:45 ` David Härdeman
2012-05-23 9:45 ` [PATCH 40/43] rc-core: use struct rc_event for all rc communication David Härdeman
` (4 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:45 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Using struct rc_event as the data unit for writes from userspace provides
more flexibility and easier future compatibility with future developments
(e.g. if rc-core grew support for some very different transmission, such
as RF transmission).
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/ene_ir.c | 24 ++++++------
drivers/media/rc/ene_ir.h | 2 -
drivers/media/rc/ir-lirc-codec.c | 12 +++---
drivers/media/rc/ite-cir.c | 19 +++++----
drivers/media/rc/mceusb.c | 10 +++--
drivers/media/rc/nuvoton-cir.c | 10 +++--
drivers/media/rc/rc-loopback.c | 10 ++++-
drivers/media/rc/rc-main.c | 18 +++------
drivers/media/rc/redrat3.c | 20 ++++++++--
drivers/media/rc/winbond-cir.c | 22 +++++------
include/media/rc-core.h | 79 +++++++++++++++++++-------------------
include/media/rc-ir-raw.h | 6 +++
12 files changed, 133 insertions(+), 99 deletions(-)
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index 2c2cfd5..9669311 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -604,7 +604,7 @@ static void ene_tx_enable(struct ene_device *dev)
static void ene_tx_disable(struct ene_device *dev)
{
ene_write_reg(dev, ENE_CIRCFG, dev->saved_conf1);
- init_ir_raw_event(&dev->tx_event);
+ dev->tx_event.val = 0;
}
@@ -614,7 +614,7 @@ static void ene_tx_sample(struct ene_device *dev)
u8 raw_tx;
/* Grab next TX sample */
- if (!dev->tx_event.duration) {
+ while (!dev->tx_event.val) {
if (!kfifo_get(&dev->rdev->txfifo, &dev->tx_event)) {
if (!dev->tx_done) {
@@ -629,19 +629,21 @@ static void ene_tx_sample(struct ene_device *dev)
}
}
- dev->tx_event.duration = DIV_ROUND_CLOSEST(dev->tx_event.duration,
- US_TO_NS(sample_period));
- if (!dev->tx_event.duration)
- dev->tx_event.duration = 1;
+ if (!is_ir_raw_timing_event(dev->tx_event))
+ continue;
+
+ dev->tx_event.val = max_t(u64, 1,
+ DIV_ROUND_CLOSEST(dev->tx_event.val,
+ US_TO_NS(sample_period)));
}
- raw_tx = min_t(unsigned, dev->tx_event.duration, ENE_CIRRLC_OUT_MASK);
- dev->tx_event.duration -= raw_tx;
+ raw_tx = min_t(unsigned, dev->tx_event.val, ENE_CIRRLC_OUT_MASK);
+ dev->tx_event.val -= raw_tx;
dbg("TX: sample %8d (%s)", raw_tx * sample_period,
- dev->tx_event.pulse ? "pulse" : "space");
+ dev->tx_event.code == RC_IR_RAW_PULSE ? "pulse" : "space");
- if (dev->tx_event.pulse)
+ if (dev->tx_event.code == RC_IR_RAW_PULSE)
raw_tx |= ENE_CIRRLC_OUT_PULSE;
ene_write_reg(dev,
@@ -953,7 +955,7 @@ static int ene_transmit(struct rc_dev *rdev)
dev->tx_reg = 0;
dev->tx_done = false;
- init_ir_raw_event(&dev->tx_event);
+ dev->tx_event.val = 0;
dbg("TX: %d samples", kfifo_len(&rdev->txfifo));
spin_lock_irqsave(&dev->hw_lock, flags);
diff --git a/drivers/media/rc/ene_ir.h b/drivers/media/rc/ene_ir.h
index 975d67a..d0898e1 100644
--- a/drivers/media/rc/ene_ir.h
+++ b/drivers/media/rc/ene_ir.h
@@ -224,7 +224,7 @@ struct ene_device {
u8 saved_conf1; /* saved FEC0 reg */
/* TX buffer */
- struct ir_raw_event tx_event; /* current sample for TX */
+ struct rc_event tx_event; /* current sample for TX */
bool tx_done; /* done transmitting */
struct completion tx_complete; /* TX completion */
struct timer_list tx_sim_timer;
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 6811db9..a5b0368 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -109,8 +109,8 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
ssize_t ret;
s64 towait;
unsigned int duration = 0; /* signal duration in us */
- DEFINE_IR_RAW_EVENT(event);
bool pulse = true;
+ struct rc_event ev;
if (!lirc || !lirc->dev)
return -EFAULT;
@@ -122,14 +122,16 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
if (n % sizeof(u32) || ((n / sizeof(u32)) % 2) == 0)
return -EINVAL;
+ ev.type = RC_IR_RAW;
+ ev.reserved = 0x0;
+
for (ret = 0; ret + sizeof(u32) <= n; ret += sizeof(u32)) {
if (copy_from_user(&value, buf + ret, sizeof(u32)))
return -EFAULT;
- event.pulse = pulse;
- event.duration = US_TO_NS(value);
- if (kfifo_in_spinlocked(&dev->txfifo, &event, 1, &dev->txlock)
- != 1)
+ ev.code = pulse ? RC_IR_RAW_PULSE : RC_IR_RAW_SPACE;
+ ev.val = US_TO_NS(value);
+ if (!kfifo_in_spinlocked(&dev->txfifo, &ev, 1, &dev->txlock))
break;
pulse = !pulse;
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 44759db..51fb845 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -390,7 +390,7 @@ static int ite_tx_ir(struct rc_dev *rcdev)
int max_rle_us, next_rle_us;
u8 last_sent[ITE_TX_FIFO_LEN];
u8 val;
- DEFINE_IR_RAW_EVENT(event);
+ struct rc_event ev;
ite_dbg("%s called", __func__);
@@ -420,14 +420,16 @@ static int ite_tx_ir(struct rc_dev *rcdev)
fifo_avail =
ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev);
- while (kfifo_get(&rcdev->txfifo, &event) && dev->in_use) {
+ while (kfifo_get(&rcdev->txfifo, &ev) && dev->in_use) {
+ if (!is_ir_raw_timing_event(ev))
+ continue;
+
/* transmit the next sample */
- remaining_us = event.duration;
+ remaining_us = ev.val;
- ite_dbg("%s: %ld",
- (event.pulse ? "pulse" : "space"),
- (long int)
- remaining_us);
+ ite_dbg("%s: %lld",
+ ev.code == RC_IR_RAW_PULSE ? "pulse" : "space",
+ (long long int)remaining_us);
/* repeat while the pulse is non-zero length */
while (remaining_us > 0 && dev->in_use) {
@@ -450,9 +452,8 @@ static int ite_tx_ir(struct rc_dev *rcdev)
val = (val - 1) & ITE_TX_RLE_MASK;
/* take into account pulse/space prefix */
- if (event.pulse)
+ if (ev.code == RC_IR_RAW_PULSE)
val |= ITE_TX_PULSE;
-
else
val |= ITE_TX_SPACE;
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index e9dda87..952ea01 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -785,7 +785,7 @@ static int mceusb_tx_ir(struct rc_dev *dev)
struct mceusb_dev *ir = dev->priv;
unsigned tmp, i = 0;
unsigned char buf[MCE_CMDBUF_SIZE]; /* MCE command buffer */
- DEFINE_IR_RAW_EVENT(event);
+ struct rc_event event;
/* MCE tx init header */
buf[i++] = MCE_CMD_PORT_IR;
@@ -793,7 +793,10 @@ static int mceusb_tx_ir(struct rc_dev *dev)
buf[i++] = ir->tx_mask;
while (kfifo_get(&dev->txfifo, &event)) {
- tmp = event.duration / US_TO_NS(MCE_TIME_UNIT);
+ if (!is_ir_raw_timing_event(event))
+ continue;
+
+ tmp = event.val / US_TO_NS(MCE_TIME_UNIT);
/* Split event into pulses/spaces <= 127 * 50us = 6.35ms */
while (tmp > 0 && i < (MCE_CMDBUF_SIZE - 1)) {
@@ -804,7 +807,8 @@ static int mceusb_tx_ir(struct rc_dev *dev)
buf[i] = min_t(unsigned, tmp, MCE_MAX_PULSE_LENGTH);
tmp -= buf[i];
- buf[i++] |= event.pulse ? MCE_PULSE_BIT : 0x00;
+ if (event.code == RC_IR_RAW_PULSE)
+ buf[i++] |= MCE_PULSE_BIT;
}
/* See if command buffer is full */
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 915074e..4c37ade 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -756,6 +756,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
struct nvt_dev *nvt = data;
u8 status, iren, cur_state;
unsigned long flags;
+ struct rc_event ev;
nvt_dbg_verbose("%s firing", __func__);
@@ -830,14 +831,15 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
spin_lock_irqsave(&nvt->tx.lock, flags);
/* Any data in tx buffer? */
- if (nvt->tx.cur_buf_num >= nvt->tx.buf_count) {
- DEFINE_IR_RAW_EVENT(event);
- if (!kfifo_get(&nvt->rdev->txfifo, &event)) {
+ while (nvt->tx.cur_buf_num >= nvt->tx.buf_count) {
+ if (!kfifo_get(&nvt->rdev->txfifo, &ev)) {
/* No more data, disable TTR interrupt */
u8 tmp = nvt_cir_reg_read(nvt, CIR_IREN);
nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN);
+ } else if (!is_ir_raw_timing_event(ev)) {
+ continue;
} else {
- unsigned sample = event.duration / 1000;
+ unsigned sample = ev.val / 1000;
nvt->tx.buf_count = sizeof(sample);
nvt->tx.cur_buf_num = 0;
memcpy(nvt->tx.buf, &sample, sizeof(sample));
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 7775b3e..45ef966 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -53,6 +53,7 @@ static int loop_tx_ir(struct rc_dev *dev)
{
struct loopback_dev *lodev = dev->priv;
u32 rxmask;
+ struct rc_event event;
DEFINE_IR_RAW_EVENT(rawir);
if (lodev->txcarrier < lodev->rxcarriermin ||
@@ -73,8 +74,15 @@ static int loop_tx_ir(struct rc_dev *dev)
return 0;
}
- while (kfifo_get(&dev->txfifo, &rawir))
+ while (kfifo_get(&dev->txfifo, &event)) {
+ if (is_ir_raw_timing_event(event))
+ continue;
+ init_ir_raw_event(&rawir);
+ rawir.duration = event.val;
+ if (event.code == RC_IR_RAW_PULSE)
+ rawir.pulse = true;
ir_raw_event_store_with_filter(dev, &rawir);
+ }
/* Fake a silence long enough to cause us to go idle */
init_ir_raw_event(&rawir);
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 14728fc..6c8bc3a 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -801,14 +801,12 @@ static ssize_t rc_write(struct file *file, const char __user *buffer,
struct rc_client *client = file->private_data;
struct rc_dev *dev = client->dev;
ssize_t ret;
- DEFINE_IR_RAW_EVENT(event);
- bool pulse = true;
- u32 value;
+ struct rc_event ev;
if (!dev->tx_ir)
return -ENOSYS;
- if ((count < sizeof(u32)) || (count % sizeof(u32)))
+ if (count < sizeof(ev))
return -EINVAL;
again:
@@ -825,16 +823,14 @@ again:
if (!dev->exist)
return -ENODEV;
- for (ret = 0; ret + sizeof(value) <= count; ret += sizeof(value)) {
- if (copy_from_user(&value, buffer + ret, sizeof(value)))
+ for (ret = 0; ret + sizeof(ev) <= count; ret += sizeof(ev)) {
+ if (copy_from_user(&ev, buffer + ret, sizeof(ev)))
return -EFAULT;
- event.duration = US_TO_NS(value);
- event.pulse = pulse;
- pulse = !pulse;
+ if (ev.reserved)
+ return -EINVAL;
- if (kfifo_in_spinlocked(&dev->txfifo, &event, 1, &dev->txlock)
- != 1)
+ if (!kfifo_in_spinlocked(&dev->txfifo, &ev, 1, &dev->txlock))
break;
}
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 394799d..760f13e 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -906,8 +906,8 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev)
{
struct redrat3_dev *rr3 = rcdev->priv;
struct device *dev = rr3->dev;
- DEFINE_IR_RAW_EVENT(event);
struct redrat3_tx_data tx;
+ struct rc_event ev;
unsigned nlens = 0, nsamples = 0, i;
int txlen, actual_len;
int ret;
@@ -924,9 +924,23 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev)
rr3->det_enabled = false;
rr3->transmitting = true;
- while (kfifo_get(&rcdev->txfifo, &event)) {
+ while (kfifo_get(&rcdev->txfifo, &ev)) {
+ if (!is_ir_raw_timing_event(ev))
+ continue;
+
/* Convert duration to RR format */
- sample = redrat3_us_to_len(event.duration / 1000);
+ sample = redrat3_us_to_len(ev.val / 1000);
+
+ if (sample < 1)
+ continue;
+
+ if (((ev.code == RC_IR_RAW_PULSE) && (nsamples % 2 == 1)) ||
+ ((ev.code == RC_IR_RAW_SPACE) && (nsamples % 2 == 0))) {
+ /* Input is not in pulse/space/pulse/space/etc format */
+ dev_err(dev, "signal invalid\n");
+ ret = -EINVAL;
+ goto out;
+ }
/* See if we already have the same sample size stored */
for (i = 0; i < nlens; i++)
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 5a240ba..76a8104 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -213,7 +213,7 @@ struct wbcir_data {
/* TX state */
enum wbcir_txstate txstate;
struct led_trigger *txtrigger;
- struct ir_raw_event txevent;
+ struct rc_event txevent;
wait_queue_head_t txwaitq;
u8 txmask;
u32 txcarrier;
@@ -403,19 +403,20 @@ wbcir_irq_tx(struct wbcir_data *data)
* X = duration, encoded as (X + 1) * 10us (i.e 10 to 1280 us)
*/
for (used = 0; used < space; used++) {
- while (data->txevent.duration == 0) {
+ while (data->txevent.val == 0) {
if (!kfifo_get(&data->dev->txfifo, &data->txevent))
break;
+ if (!is_ir_raw_timing_event(data->txevent))
+ continue;
/* Convert duration to multiples of 10us */
- data->txevent.duration =
- DIV_ROUND_CLOSEST(data->txevent.duration,
- 10 * 1000);
+ data->txevent.val =
+ DIV_ROUND_CLOSEST(data->txevent.val, 10 * 1000);
}
- byte = min_t(u32, 0x80, data->txevent.duration);
- data->txevent.duration -= byte;
+ byte = min_t(u32, 0x80, data->txevent.val);
+ data->txevent.val -= byte;
byte--;
- byte |= data->txevent.pulse ? 0x80 : 0x00;
+ byte |= data->txevent.code == RC_IR_RAW_PULSE ? 0x80 : 0x00;
bytes[used] = byte;
}
@@ -429,8 +430,7 @@ wbcir_irq_tx(struct wbcir_data *data)
wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR);
led_trigger_event(data->txtrigger, LED_OFF);
wake_up(&data->txwaitq);
- } else if (data->txevent.duration == 0 &&
- kfifo_is_empty(&data->dev->txfifo)) {
+ } else if (data->txevent.val == 0 && kfifo_is_empty(&data->dev->txfifo)) {
/* At the end of transmission, tell the hw before last byte */
outsb(data->sbase + WBCIR_REG_SP3_TXDATA, bytes, used - 1);
outb(WBCIR_TX_EOT, data->sbase + WBCIR_REG_SP3_ASCR);
@@ -594,7 +594,7 @@ wbcir_tx(struct rc_dev *dev)
}
/* Fill the TX fifo once, the irq handler will do the rest */
- init_ir_raw_event(&data->txevent);
+ data->txevent.val = 0;
wbcir_irq_tx(data);
/* Wait for the TX to complete */
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index f2ff7f7..d8cad87 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -199,7 +199,6 @@ struct rc_keymap_entry {
};
};
-#define RC_TX_KFIFO_SIZE 1024
struct ir_raw_event {
union {
u32 duration;
@@ -216,6 +215,43 @@ struct ir_raw_event {
unsigned carrier_report:1;
};
+/**
+ * struct rc_event - used to communicate rc events to userspace
+ * @type: the event type
+ * @code: the event code (type specific)
+ * @reserved: zero for now
+ * @val: the event value (type and code specific)
+ */
+struct rc_event {
+ __u16 type;
+ __u16 code;
+ __u32 reserved;
+ __u64 val;
+} __packed;
+
+/* rc_event.type value */
+#define RC_DEBUG 0x0
+#define RC_CORE 0x1
+#define RC_KEY 0x2
+#define RC_IR_RAW 0x3
+
+/* RC_CORE codes */
+#define RC_CORE_DROPPED 0x0
+
+/* RC_KEY codes */
+#define RC_KEY_REPEAT 0x0
+#define RC_KEY_PROTOCOL 0x1
+#define RC_KEY_SCANCODE 0x2
+#define RC_KEY_TOGGLE 0x3
+
+/* RC_IR_RAW codes */
+#define RC_IR_RAW_SPACE 0x0
+#define RC_IR_RAW_PULSE 0x1
+#define RC_IR_RAW_START 0x2
+#define RC_IR_RAW_STOP 0x3
+#define RC_IR_RAW_RESET 0x4
+#define RC_IR_RAW_CARRIER 0x5
+#define RC_IR_RAW_DUTY_CYCLE 0x6
/**
* struct rc_dev - represents a remote control device
@@ -279,6 +315,7 @@ struct ir_raw_event {
* @set_ir_tx: allow driver to change tx settings
*/
#define RC_MAX_KEYTABLES 32
+#define RC_TX_KFIFO_SIZE 1024
struct rc_dev {
struct device dev;
const char *input_name;
@@ -294,7 +331,7 @@ struct rc_dev {
struct list_head client_list;
spinlock_t client_lock;
unsigned users;
- DECLARE_KFIFO_PTR(txfifo, struct ir_raw_event);
+ DECLARE_KFIFO_PTR(txfifo, struct rc_event);
spinlock_t txlock;
wait_queue_head_t txwait;
wait_queue_head_t rxwait;
@@ -374,44 +411,6 @@ struct rc_keytable {
#define to_rc_dev(d) container_of(d, struct rc_dev, dev)
-/* rc_event.type value */
-#define RC_DEBUG 0x0
-#define RC_CORE 0x1
-#define RC_KEY 0x2
-#define RC_IR_RAW 0x3
-
-/* RC_CORE codes */
-#define RC_CORE_DROPPED 0x0
-
-/* RC_KEY codes */
-#define RC_KEY_REPEAT 0x0
-#define RC_KEY_PROTOCOL 0x1
-#define RC_KEY_SCANCODE 0x2
-#define RC_KEY_TOGGLE 0x3
-
-/* RC_IR_RAW codes */
-#define RC_IR_RAW_SPACE 0x0
-#define RC_IR_RAW_PULSE 0x1
-#define RC_IR_RAW_START 0x2
-#define RC_IR_RAW_STOP 0x3
-#define RC_IR_RAW_RESET 0x4
-#define RC_IR_RAW_CARRIER 0x5
-#define RC_IR_RAW_DUTY_CYCLE 0x6
-
-/**
- * struct rc_event - used to communicate rc events to userspace
- * @type: the event type
- * @code: the event code (type specific)
- * @reserved: zero for now
- * @val: the event value (type and code specific)
- */
-struct rc_event {
- __u16 type;
- __u16 code;
- __u32 reserved;
- __u64 val;
-} __packed;
-
/*
* From rc-main.c
* Those functions can be used on any type of Remote Controller. They
diff --git a/include/media/rc-ir-raw.h b/include/media/rc-ir-raw.h
index 4c3fe78..7fd0693 100644
--- a/include/media/rc-ir-raw.h
+++ b/include/media/rc-ir-raw.h
@@ -65,4 +65,10 @@ static inline void ir_raw_event_reset(struct rc_dev *dev)
ir_raw_event_handle(dev);
}
+static inline bool is_ir_raw_timing_event(struct rc_event ev)
+{
+ return (ev.type == RC_IR_RAW &&
+ (ev.code == RC_IR_RAW_PULSE || ev.code == RC_IR_RAW_SPACE));
+}
+
#endif /* _RC_IR_RAW */
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 40/43] rc-core: use struct rc_event for all rc communication
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (38 preceding siblings ...)
2012-05-23 9:45 ` [PATCH 39/43] rc-core: use struct rc_event to signal TX events from userspace David Härdeman
@ 2012-05-23 9:45 ` David Härdeman
2012-05-23 9:45 ` [PATCH 41/43] rc-core: add keytable events David Härdeman
` (3 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:45 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Remove struct ir_raw_event and use struct rc_event in all stages
of IR processing. This should help future flexibility and also
cuts down on the confusing number of structs that are flying
around in rc-*.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/dvb/dvb-usb/technisat-usb2.c | 15 +++-
drivers/media/dvb/siano/smsir.c | 7 +-
drivers/media/rc/ene_ir.c | 12 ++-
drivers/media/rc/fintek-cir.c | 18 +++--
drivers/media/rc/ir-jvc-decoder.c | 48 +++++++-------
drivers/media/rc/ir-lirc-codec.c | 28 ++++----
drivers/media/rc/ir-mce_kbd-decoder.c | 34 +++++-----
drivers/media/rc/ir-nec-decoder.c | 51 +++++++--------
drivers/media/rc/ir-rc5-decoder.c | 32 +++++----
drivers/media/rc/ir-rc6-decoder.c | 48 +++++++-------
drivers/media/rc/ir-sanyo-decoder.c | 46 +++++++------
drivers/media/rc/ir-sony-decoder.c | 42 ++++++------
drivers/media/rc/ite-cir.c | 19 ++---
drivers/media/rc/ite-cir.h | 2 -
drivers/media/rc/mceusb.c | 15 +++-
drivers/media/rc/nuvoton-cir.c | 18 +++--
drivers/media/rc/rc-core-priv.h | 33 +++++----
drivers/media/rc/rc-ir-raw.c | 90 +++++++++++++++-----------
drivers/media/rc/rc-loopback.c | 21 ++----
drivers/media/rc/redrat3.c | 33 ++++-----
drivers/media/rc/streamzap.c | 62 +++++++++---------
drivers/media/rc/winbond-cir.c | 7 +-
drivers/media/video/cx23885/cx23885-input.c | 11 +--
drivers/media/video/cx23885/cx23888-ir.c | 91 ++++++++++++++------------
drivers/media/video/cx25840/cx25840-ir.c | 94 ++++++++++++++-------------
drivers/media/video/cx88/cx88-input.c | 13 +++-
include/media/rc-core.h | 16 -----
include/media/rc-ir-raw.h | 34 +++++-----
28 files changed, 477 insertions(+), 463 deletions(-)
diff --git a/drivers/media/dvb/dvb-usb/technisat-usb2.c b/drivers/media/dvb/dvb-usb/technisat-usb2.c
index 3b8752a..5860009 100644
--- a/drivers/media/dvb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/dvb/dvb-usb/technisat-usb2.c
@@ -593,7 +593,7 @@ static int technisat_usb2_get_ir(struct dvb_usb_device *d)
{
u8 buf[62], *b;
int ret;
- struct ir_raw_event ev;
+ DEFINE_IR_RAW_EVENT(ev);
buf[0] = GET_IR_DATA_VENDOR_REQUEST;
buf[1] = 0x08;
@@ -636,16 +636,19 @@ unlock:
debug_dump(b, ret, deb_rc);
#endif
- ev.pulse = 0;
while (1) {
- ev.pulse = !ev.pulse;
- ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000;
+ if (ev.code == RC_IR_RAW_SPACE)
+ ev.code = RC_IR_RAW_PULSE;
+ else
+ ev.code = RC_IR_RAW_SPACE;
+
+ ev.val = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000;
ir_raw_event_store(d->rc_dev, &ev);
b++;
if (*b == 0xff) {
- ev.pulse = 0;
- ev.duration = 888888*2;
+ ev.code = RC_IR_RAW_SPACE;
+ ev.val = 888888*2;
ir_raw_event_store(d->rc_dev, &ev);
break;
}
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
index c9a627d..e619c16 100644
--- a/drivers/media/dvb/siano/smsir.c
+++ b/drivers/media/dvb/siano/smsir.c
@@ -38,12 +38,11 @@ void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
{
int i;
const s32 *samples = (const void *)buf;
+ DEFINE_IR_RAW_EVENT(ev);
for (i = 0; i < len >> 2; i++) {
- DEFINE_IR_RAW_EVENT(ev);
-
- ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
- ev.pulse = (samples[i] > 0) ? false : true;
+ ev.val = US_TO_NS(abs(samples[i]));
+ ev.code = (samples[i] > 0) ? RC_IR_RAW_SPACE : RC_IR_RAW_PULSE;
ir_raw_event_store(coredev->ir.dev, &ev);
}
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index 9669311..51e704f 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -353,9 +353,11 @@ static void ene_rx_sense_carrier(struct ene_device *dev)
dbg("RX: sensed carrier = %d Hz, duty cycle %d%%",
carrier, duty_cycle);
if (dev->carrier_detect_enabled) {
- ev.carrier_report = true;
- ev.carrier = carrier;
- ev.duty_cycle = duty_cycle;
+ ev.code = RC_IR_RAW_CARRIER;
+ ev.val = carrier;
+ ir_raw_event_store(dev->rdev, &ev);
+ ev.code = RC_IR_RAW_DUTY_CYCLE;
+ ev.val = duty_cycle;
ir_raw_event_store(dev->rdev, &ev);
}
}
@@ -795,8 +797,8 @@ static irqreturn_t ene_isr(int irq, void *data)
dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
- ev.duration = US_TO_NS(hw_sample);
- ev.pulse = pulse;
+ ev.val = US_TO_NS(hw_sample);
+ ev.code = pulse ? RC_IR_RAW_PULSE : RC_IR_RAW_SPACE;
ir_raw_event_store_with_filter(dev->rdev, &ev);
}
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index ac949ae..0eabae0 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -289,7 +289,7 @@ static int fintek_cmdsize(u8 cmd, u8 subcmd)
/* process ir data stored in driver buffer */
static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
{
- DEFINE_IR_RAW_EVENT(rawir);
+ DEFINE_IR_RAW_EVENT(ev);
u8 sample;
int i;
@@ -320,15 +320,17 @@ static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
break;
case PARSE_IRDATA:
fintek->rem--;
- init_ir_raw_event(&rawir);
- rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
- rawir.duration = US_TO_NS((sample & BUF_SAMPLE_MASK)
+ init_ir_raw_event(&ev);
+ ev.code = RC_IR_RAW_SPACE;
+ if (sample & BUF_PULSE_BIT)
+ ev.code = RC_IR_RAW_PULSE;
+ ev.val = US_TO_NS((sample & BUF_SAMPLE_MASK)
* CIR_SAMPLE_PERIOD);
- fit_dbg("Storing %s with duration %d",
- rawir.pulse ? "pulse" : "space",
- rawir.duration);
- ir_raw_event_store_with_filter(fintek->rdev, &rawir);
+ fit_dbg("Storing %s with duration %llu",
+ ev.code == RC_IR_RAW_PULSE ? "pulse" : "space",
+ (long long unsigned)ev.val);
+ ir_raw_event_store_with_filter(fintek->rdev, &ev);
break;
}
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 30bcf18..dd1c8db 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -39,37 +39,39 @@ enum jvc_state {
/**
* ir_jvc_decode() - Decode one JVC pulse or space
* @dev: the struct rc_dev descriptor of the device
- * @duration: the struct ir_raw_event descriptor of the pulse/space
+ * @ev: the struct rc_event descriptor of the event
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_jvc_decode(struct rc_dev *dev, struct rc_event ev)
{
struct jvc_dec *data = &dev->raw->jvc;
if (!(dev->enabled_protocols & RC_BIT_JVC))
return 0;
- if (!is_timing_event(ev)) {
- if (ev.reset)
- data->state = STATE_INACTIVE;
+ if (ev.code == RC_IR_RAW_RESET) {
+ data->state = STATE_INACTIVE;
return 0;
}
- if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2))
+ if (!is_ir_raw_timing_event(ev))
+ return 0;
+
+ if (!geq_margin(ev.val, JVC_UNIT, JVC_UNIT / 2))
goto out;
IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, TO_US(ev.val), TO_STR(ev.code));
again:
switch (data->state) {
case STATE_INACTIVE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
- if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
+ if (!eq_margin(ev.val, JVC_HEADER_PULSE, JVC_UNIT / 2))
break;
data->count = 0;
@@ -79,34 +81,34 @@ again:
return 0;
case STATE_HEADER_SPACE:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
- if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2))
+ if (!eq_margin(ev.val, JVC_HEADER_SPACE, JVC_UNIT / 2))
break;
data->state = STATE_BIT_PULSE;
return 0;
case STATE_BIT_PULSE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
- if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2))
+ if (!eq_margin(ev.val, JVC_BIT_PULSE, JVC_UNIT / 2))
break;
data->state = STATE_BIT_SPACE;
return 0;
case STATE_BIT_SPACE:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
data->bits <<= 1;
- if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
+ if (eq_margin(ev.val, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
data->bits |= 1;
decrease_duration(&ev, JVC_BIT_1_SPACE);
- } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
+ } else if (eq_margin(ev.val, JVC_BIT_0_SPACE, JVC_UNIT / 2))
decrease_duration(&ev, JVC_BIT_0_SPACE);
else
break;
@@ -119,20 +121,20 @@ again:
return 0;
case STATE_TRAILER_PULSE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
- if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2))
+ if (!eq_margin(ev.val, JVC_TRAILER_PULSE, JVC_UNIT / 2))
break;
data->state = STATE_TRAILER_SPACE;
return 0;
case STATE_TRAILER_SPACE:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
- if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2))
+ if (!geq_margin(ev.val, JVC_TRAILER_SPACE, JVC_UNIT / 2))
break;
if (data->first) {
@@ -156,10 +158,10 @@ again:
return 0;
case STATE_CHECK_REPEAT:
- if (!ev.pulse)
+ if (is_space(ev))
break;
- if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
+ if (eq_margin(ev.val, JVC_HEADER_PULSE, JVC_UNIT / 2))
data->state = STATE_INACTIVE;
else
data->state = STATE_BIT_PULSE;
@@ -168,7 +170,7 @@ again:
out:
IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, TO_US(ev.val), TO_STR(ev.code));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index a5b0368..52b27db 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -25,12 +25,12 @@
/**
* ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the
* lircd userspace daemon for decoding.
- * @input_dev: the struct rc_dev descriptor of the device
- * @duration: the struct ir_raw_event descriptor of the pulse/space
+ * @dev: the struct rc_dev descriptor of the device
+ * @ev: the struct rc_event descriptor of the event
*
* 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)
+static int ir_lirc_decode(struct rc_dev *dev, struct rc_event ev)
{
struct lirc_codec *lirc = &dev->raw->lirc;
int sample;
@@ -42,29 +42,29 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
return -EINVAL;
/* Packet start */
- if (ev.reset)
+ if (ev.code == RC_IR_RAW_RESET)
return 0;
/* Carrier reports */
- if (ev.carrier_report) {
- sample = LIRC_FREQUENCY(ev.carrier);
+ if (ev.code == RC_IR_RAW_CARRIER) {
+ sample = LIRC_FREQUENCY(ev.val);
IR_dprintk(2, "carrier report (freq: %d)\n", sample);
/* Packet end */
- } else if (ev.timeout) {
+ } else if (ev.code == RC_IR_RAW_STOP) {
if (lirc->gap)
return 0;
lirc->gap_start = ktime_get();
lirc->gap = true;
- lirc->gap_duration = ev.duration;
+ lirc->gap_duration = 0;
if (!lirc->send_timeout_reports)
return 0;
- sample = LIRC_TIMEOUT(ev.duration / 1000);
- IR_dprintk(2, "timeout report (duration: %d)\n", sample);
+ sample = LIRC_TIMEOUT(0);
+ IR_dprintk(2, "timeout report\n");
/* Normal sample */
} else {
@@ -86,10 +86,10 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
lirc->gap = false;
}
- sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
- LIRC_SPACE(ev.duration / 1000);
+ sample = is_pulse(ev) ? LIRC_PULSE(ev.val / 1000) :
+ LIRC_SPACE(ev.val / 1000);
IR_dprintk(2, "delivering %uus %s to lirc_dev\n",
- TO_US(ev.duration), TO_STR(ev.pulse));
+ TO_US(ev.val), TO_STR(ev.code));
}
lirc_buffer_write(dev->raw->lirc.drv->rbuf,
@@ -410,7 +410,7 @@ static int ir_lirc_register(struct rc_dev *dev)
drv->rbuf = rbuf;
drv->set_use_inc = &ir_lirc_open;
drv->set_use_dec = &ir_lirc_close;
- drv->code_length = sizeof(struct ir_raw_event) * 8;
+ drv->code_length = sizeof(struct rc_event) * 8;
drv->fops = &lirc_fops;
drv->dev = &dev->dev;
drv->owner = THIS_MODULE;
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 9f3c9b5..f3d7dba 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -206,11 +206,11 @@ static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode)
/**
* ir_mce_kbd_decode() - Decode one mce_kbd pulse or space
* @dev: the struct rc_dev descriptor of the device
- * @ev: the struct ir_raw_event descriptor of the pulse/space
+ * @ev: the struct rc_event descriptor of the event
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_mce_kbd_decode(struct rc_dev *dev, struct rc_event ev)
{
struct mce_kbd_dec *data = &dev->raw->mce_kbd;
u32 scancode;
@@ -219,32 +219,34 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (!(dev->enabled_protocols & RC_BIT_MCE_KBD))
return 0;
- if (!is_timing_event(ev)) {
- if (ev.reset)
- data->state = STATE_INACTIVE;
+ if (ev.code == RC_IR_RAW_RESET) {
+ data->state = STATE_INACTIVE;
return 0;
}
- if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
+ if (!is_ir_raw_timing_event(ev))
+ return 0;
+
+ if (!geq_margin(ev.val, MCIR2_UNIT, MCIR2_UNIT / 2))
goto out;
again:
IR_dprintk(2, "started at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, TO_US(ev.val), TO_STR(ev.code));
- if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
+ if (!geq_margin(ev.val, MCIR2_UNIT, MCIR2_UNIT / 2))
return 0;
switch (data->state) {
case STATE_INACTIVE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
/* Note: larger margin on first pulse since each MCIR2_UNIT
is quite short and some hardware takes some time to
adjust to the signal */
- if (!eq_margin(ev.duration, MCIR2_PREFIX_PULSE, MCIR2_UNIT))
+ if (!eq_margin(ev.val, MCIR2_PREFIX_PULSE, MCIR2_UNIT))
break;
data->state = STATE_HEADER_BIT_START;
@@ -253,11 +255,11 @@ again:
return 0;
case STATE_HEADER_BIT_START:
- if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
+ if (geq_margin(ev.val, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
break;
data->header <<= 1;
- if (ev.pulse)
+ if (is_pulse(ev))
data->header |= 1;
data->count++;
data->state = STATE_HEADER_BIT_END;
@@ -292,11 +294,11 @@ again:
goto again;
case STATE_BODY_BIT_START:
- if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
+ if (geq_margin(ev.val, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
break;
data->body <<= 1;
- if (ev.pulse)
+ if (is_pulse(ev))
data->body |= 1;
data->count++;
data->state = STATE_BODY_BIT_END;
@@ -315,7 +317,7 @@ again:
goto again;
case STATE_FINISHED:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
switch (data->wanted_bits) {
@@ -348,7 +350,7 @@ again:
out:
IR_dprintk(1, "failed at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, TO_US(ev.val), TO_STR(ev.code));
data->state = STATE_INACTIVE;
input_sync(data->idev);
return -EINVAL;
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index c92b229..cf2feea 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -41,11 +41,11 @@ enum nec_state {
/**
* ir_nec_decode() - Decode one NEC pulse or space
* @dev: the struct rc_dev descriptor of the device
- * @duration: the struct ir_raw_event descriptor of the pulse/space
+ * @ev: the struct rc_event descriptor of the event
*
- * This function returns -EINVAL if the pulse violates the state machine
+ * This function returns -EINVAL if the event violates the state machine
*/
-static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_nec_decode(struct rc_dev *dev, struct rc_event ev)
{
struct nec_dec *data = &dev->raw->nec;
u32 scancode;
@@ -54,25 +54,27 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (!(dev->enabled_protocols & RC_BIT_NEC))
return 0;
- if (!is_timing_event(ev)) {
- if (ev.reset)
- data->state = STATE_INACTIVE;
+ if (ev.code == RC_IR_RAW_RESET) {
+ data->state = STATE_INACTIVE;
return 0;
}
+ if (!is_ir_raw_timing_event(ev))
+ return 0;
+
IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, TO_US(ev.val), TO_STR(ev.code));
switch (data->state) {
case STATE_INACTIVE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
- if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2)) {
+ if (eq_margin(ev.val, NEC_HEADER_PULSE, NEC_UNIT / 2)) {
data->is_nec_x = false;
data->necx_repeat = false;
- } else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))
+ } else if (eq_margin(ev.val, NECX_HEADER_PULSE, NEC_UNIT / 2))
data->is_nec_x = true;
else
break;
@@ -82,13 +84,13 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
return 0;
case STATE_HEADER_SPACE:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
- if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT / 2)) {
+ if (eq_margin(ev.val, NEC_HEADER_SPACE, NEC_UNIT / 2)) {
data->state = STATE_BIT_PULSE;
return 0;
- } else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
+ } else if (eq_margin(ev.val, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
rc_repeat(dev);
IR_dprintk(1, "Repeat last key\n");
data->state = STATE_TRAILER_PULSE;
@@ -98,22 +100,21 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
break;
case STATE_BIT_PULSE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
- if (!eq_margin(ev.duration, NEC_BIT_PULSE, NEC_UNIT / 2))
+ if (!eq_margin(ev.val, NEC_BIT_PULSE, NEC_UNIT / 2))
break;
data->state = STATE_BIT_SPACE;
return 0;
case STATE_BIT_SPACE:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
if (data->necx_repeat && data->count == NECX_REPEAT_BITS &&
- geq_margin(ev.duration,
- NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
+ geq_margin(ev.val, NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
IR_dprintk(1, "Repeat last key\n");
rc_repeat(dev);
data->state = STATE_INACTIVE;
@@ -123,9 +124,9 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
data->necx_repeat = false;
data->bits <<= 1;
- if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2))
+ if (eq_margin(ev.val, NEC_BIT_1_SPACE, NEC_UNIT / 2))
data->bits |= 1;
- else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
+ else if (!eq_margin(ev.val, NEC_BIT_0_SPACE, NEC_UNIT / 2))
break;
data->count++;
@@ -137,20 +138,20 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
return 0;
case STATE_TRAILER_PULSE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
- if (!eq_margin(ev.duration, NEC_TRAILER_PULSE, NEC_UNIT / 2))
+ if (!eq_margin(ev.val, NEC_TRAILER_PULSE, NEC_UNIT / 2))
break;
data->state = STATE_TRAILER_SPACE;
return 0;
case STATE_TRAILER_SPACE:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
- if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
+ if (!geq_margin(ev.val, NEC_TRAILER_SPACE, NEC_UNIT / 2))
break;
address = bitrev8((data->bits >> 24) & 0xff);
@@ -171,7 +172,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
IR_dprintk(1, "NEC decode failed at count %d state %d (%uus %s)\n",
- data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->count, data->state, TO_US(ev.val), TO_STR(ev.code));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 9594b8f..c11eced 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -42,11 +42,11 @@ enum rc5_state {
/**
* ir_rc5_decode() - Decode one RC-5 pulse or space
* @dev: the struct rc_dev descriptor of the device
- * @ev: the struct ir_raw_event descriptor of the pulse/space
+ * @ev: the struct rc_event descriptor of the event
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_rc5_decode(struct rc_dev *dev, struct rc_event ev)
{
struct rc5_dec *data = &dev->raw->rc5;
u8 toggle;
@@ -56,26 +56,28 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X)))
return 0;
- if (!is_timing_event(ev)) {
- if (ev.reset)
- data->state = STATE_INACTIVE;
+ if (ev.code == RC_IR_RAW_RESET) {
+ data->state = STATE_INACTIVE;
return 0;
}
- if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
+ if (!is_ir_raw_timing_event(ev))
+ return 0;
+
+ if (!geq_margin(ev.val, RC5_UNIT, RC5_UNIT / 2))
goto out;
again:
IR_dprintk(2, "RC5(x) decode started at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, TO_US(ev.val), TO_STR(ev.code));
- if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
+ if (!geq_margin(ev.val, RC5_UNIT, RC5_UNIT / 2))
return 0;
switch (data->state) {
case STATE_INACTIVE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
data->state = STATE_BIT_START;
@@ -84,16 +86,16 @@ again:
goto again;
case STATE_BIT_START:
- if (!ev.pulse && geq_margin(ev.duration, RC5_TRAILER, RC5_UNIT / 2)) {
+ if (is_space(ev) && geq_margin(ev.val, RC5_TRAILER, RC5_UNIT / 2)) {
data->state = STATE_FINISHED;
goto again;
}
- if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
+ if (!eq_margin(ev.val, RC5_BIT_START, RC5_UNIT / 2))
break;
data->bits <<= 1;
- if (!ev.pulse)
+ if (is_space(ev))
data->bits |= 1;
data->count++;
data->state = STATE_BIT_END;
@@ -112,7 +114,7 @@ again:
goto again;
case STATE_CHECK_RC5X:
- if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
+ if (is_space(ev) && geq_margin(ev.val, RC5X_SPACE, RC5_UNIT / 2)) {
data->is_rc5x = true;
decrease_duration(&ev, RC5X_SPACE);
} else
@@ -121,7 +123,7 @@ again:
goto again;
case STATE_FINISHED:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
if (data->is_rc5x && data->count == RC5X_NBITS) {
@@ -166,7 +168,7 @@ again:
out:
IR_dprintk(1, "RC5(x) decode failed at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, TO_US(ev.val), TO_STR(ev.code));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index 571107e..daf0c23 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -79,11 +79,11 @@ static enum rc6_mode rc6_mode(struct rc6_dec *data)
/**
* ir_rc6_decode() - Decode one RC6 pulse or space
* @dev: the struct rc_dev descriptor of the device
- * @ev: the struct ir_raw_event descriptor of the pulse/space
+ * @ev: the struct rc_event descriptor of the event
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_rc6_decode(struct rc_dev *dev, struct rc_event ev)
{
struct rc6_dec *data = &dev->raw->rc6;
u32 scancode;
@@ -95,32 +95,34 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE)))
return 0;
- if (!is_timing_event(ev)) {
- if (ev.reset)
- data->state = STATE_INACTIVE;
+ if (ev.code == RC_IR_RAW_RESET) {
+ data->state = STATE_INACTIVE;
return 0;
}
- if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
+ if (!is_ir_raw_timing_event(ev))
+ return 0;
+
+ if (!geq_margin(ev.val, RC6_UNIT, RC6_UNIT / 2))
goto out;
again:
IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, TO_US(ev.val), TO_STR(ev.code));
- if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
+ if (!geq_margin(ev.val, RC6_UNIT, RC6_UNIT / 2))
return 0;
switch (data->state) {
case STATE_INACTIVE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
/* Note: larger margin on first pulse since each RC6_UNIT
is quite short and some hardware takes some time to
adjust to the signal */
- if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT))
+ if (!eq_margin(ev.val, RC6_PREFIX_PULSE, RC6_UNIT))
break;
data->state = STATE_PREFIX_SPACE;
@@ -128,10 +130,10 @@ again:
return 0;
case STATE_PREFIX_SPACE:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
- if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2))
+ if (!eq_margin(ev.val, RC6_PREFIX_SPACE, RC6_UNIT / 2))
break;
data->state = STATE_HEADER_BIT_START;
@@ -139,11 +141,11 @@ again:
return 0;
case STATE_HEADER_BIT_START:
- if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
+ if (!eq_margin(ev.val, RC6_BIT_START, RC6_UNIT / 2))
break;
data->header <<= 1;
- if (ev.pulse)
+ if (is_pulse(ev))
data->header |= 1;
data->count++;
data->state = STATE_HEADER_BIT_END;
@@ -162,16 +164,16 @@ again:
goto again;
case STATE_TOGGLE_START:
- if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2))
+ if (!eq_margin(ev.val, RC6_TOGGLE_START, RC6_UNIT / 2))
break;
- data->toggle = ev.pulse;
+ data->toggle = is_pulse(ev);
data->state = STATE_TOGGLE_END;
return 0;
case STATE_TOGGLE_END:
if (!is_transition(&ev, &dev->raw->prev_ev) ||
- !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
+ !geq_margin(ev.val, RC6_TOGGLE_END, RC6_UNIT / 2))
break;
if (!(data->header & RC6_STARTBIT_MASK)) {
@@ -198,17 +200,17 @@ again:
goto again;
case STATE_BODY_BIT_START:
- if (eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) {
+ if (eq_margin(ev.val, RC6_BIT_START, RC6_UNIT / 2)) {
/* Discard LSB's that won't fit in data->body */
if (data->count++ < CHAR_BIT * sizeof data->body) {
data->body <<= 1;
- if (ev.pulse)
+ if (is_pulse(ev))
data->body |= 1;
}
data->state = STATE_BODY_BIT_END;
return 0;
- } else if (RC6_MODE_6A == rc6_mode(data) && !ev.pulse &&
- geq_margin(ev.duration, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
+ } else if (RC6_MODE_6A == rc6_mode(data) && is_space(ev) &&
+ geq_margin(ev.val, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) {
data->state = STATE_FINISHED;
goto again;
}
@@ -227,7 +229,7 @@ again:
goto again;
case STATE_FINISHED:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
switch (rc6_mode(data)) {
@@ -277,7 +279,7 @@ again:
out:
IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, TO_US(ev.val), TO_STR(ev.code));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index 17ee339..4cdbd6d 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -48,11 +48,11 @@ enum sanyo_state {
/**
* ir_sanyo_decode() - Decode one SANYO pulse or space
* @dev: the struct rc_dev descriptor of the device
- * @duration: the struct ir_raw_event descriptor of the pulse/space
+ * @ev: the struct rc_event descriptor of the event
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_sanyo_decode(struct rc_dev *dev, struct rc_event ev)
{
struct sanyo_dec *data = &dev->raw->sanyo;
u32 scancode;
@@ -61,24 +61,24 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (!(dev->enabled_protocols & RC_BIT_SANYO))
return 0;
- if (!is_timing_event(ev)) {
- if (ev.reset) {
- IR_dprintk(1, "SANYO event reset received. reset to state 0\n");
- data->state = STATE_INACTIVE;
- }
+ if (ev.code == RC_IR_RAW_RESET) {
+ data->state = STATE_INACTIVE;
return 0;
}
+ if (!is_ir_raw_timing_event(ev))
+ return 0;
+
IR_dprintk(2, "SANYO decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, TO_US(ev.val), TO_STR(ev.code));
switch (data->state) {
case STATE_INACTIVE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
- if (eq_margin(ev.duration, SANYO_HEADER_PULSE, SANYO_UNIT / 2)) {
+ if (eq_margin(ev.val, SANYO_HEADER_PULSE, SANYO_UNIT / 2)) {
data->count = 0;
data->state = STATE_HEADER_SPACE;
return 0;
@@ -87,10 +87,10 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
case STATE_HEADER_SPACE:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
- if (eq_margin(ev.duration, SANYO_HEADER_SPACE, SANYO_UNIT / 2)) {
+ if (eq_margin(ev.val, SANYO_HEADER_SPACE, SANYO_UNIT / 2)) {
data->state = STATE_BIT_PULSE;
return 0;
}
@@ -98,20 +98,20 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
break;
case STATE_BIT_PULSE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
- if (!eq_margin(ev.duration, SANYO_BIT_PULSE, SANYO_UNIT / 2))
+ if (!eq_margin(ev.val, SANYO_BIT_PULSE, SANYO_UNIT / 2))
break;
data->state = STATE_BIT_SPACE;
return 0;
case STATE_BIT_SPACE:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
- if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
+ if (!data->count && geq_margin(ev.val, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
rc_repeat(dev);
IR_dprintk(1, "SANYO repeat last key\n");
data->state = STATE_INACTIVE;
@@ -119,9 +119,9 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
data->bits <<= 1;
- if (eq_margin(ev.duration, SANYO_BIT_1_SPACE, SANYO_UNIT / 2))
+ if (eq_margin(ev.val, SANYO_BIT_1_SPACE, SANYO_UNIT / 2))
data->bits |= 1;
- else if (!eq_margin(ev.duration, SANYO_BIT_0_SPACE, SANYO_UNIT / 2))
+ else if (!eq_margin(ev.val, SANYO_BIT_0_SPACE, SANYO_UNIT / 2))
break;
data->count++;
@@ -133,20 +133,20 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
return 0;
case STATE_TRAILER_PULSE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
- if (!eq_margin(ev.duration, SANYO_TRAILER_PULSE, SANYO_UNIT / 2))
+ if (!eq_margin(ev.val, SANYO_TRAILER_PULSE, SANYO_UNIT / 2))
break;
data->state = STATE_TRAILER_SPACE;
return 0;
case STATE_TRAILER_SPACE:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
- if (!geq_margin(ev.duration, SANYO_TRAILER_SPACE, SANYO_UNIT / 2))
+ if (!geq_margin(ev.val, SANYO_TRAILER_SPACE, SANYO_UNIT / 2))
break;
address = bitrev16((data->bits >> 29) & 0x1fff) >> 3;
@@ -169,7 +169,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
IR_dprintk(1, "SANYO decode failed at count %d state %d (%uus %s)\n",
- data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->count, data->state, TO_US(ev.val), TO_STR(ev.code));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index f360e40..8f1be85 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -35,11 +35,11 @@ enum sony_state {
/**
* ir_sony_decode() - Decode one Sony pulse or space
* @dev: the struct rc_dev descriptor of the device
- * @ev: the struct ir_raw_event descriptor of the pulse/space
+ * @ev: the struct rc_event descriptor of the event
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
+static int ir_sony_decode(struct rc_dev *dev, struct rc_event ev)
{
struct sony_dec *data = &dev->raw->sony;
u32 scancode;
@@ -50,25 +50,27 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
(RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20)))
return 0;
- if (!is_timing_event(ev)) {
- if (ev.reset)
- data->state = STATE_INACTIVE;
+ if (ev.code == RC_IR_RAW_RESET) {
+ data->state = STATE_INACTIVE;
return 0;
}
- if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2))
+ if (!is_ir_raw_timing_event(ev))
+ return 0;
+
+ if (!geq_margin(ev.val, SONY_UNIT, SONY_UNIT / 2))
goto out;
IR_dprintk(2, "Sony decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, TO_US(ev.val), TO_STR(ev.code));
switch (data->state) {
case STATE_INACTIVE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
- if (!eq_margin(ev.duration, SONY_HEADER_PULSE, SONY_UNIT / 2))
+ if (!eq_margin(ev.val, SONY_HEADER_PULSE, SONY_UNIT / 2))
break;
data->count = 0;
@@ -76,23 +78,23 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
return 0;
case STATE_HEADER_SPACE:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
- if (!eq_margin(ev.duration, SONY_HEADER_SPACE, SONY_UNIT / 2))
+ if (!eq_margin(ev.val, SONY_HEADER_SPACE, SONY_UNIT / 2))
break;
data->state = STATE_BIT_PULSE;
return 0;
case STATE_BIT_PULSE:
- if (!ev.pulse)
+ if (is_space(ev))
break;
data->bits <<= 1;
- if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2))
+ if (eq_margin(ev.val, SONY_BIT_1_PULSE, SONY_UNIT / 2))
data->bits |= 1;
- else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2))
+ else if (!eq_margin(ev.val, SONY_BIT_0_PULSE, SONY_UNIT / 2))
break;
data->count++;
@@ -100,15 +102,15 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
return 0;
case STATE_BIT_SPACE:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
- if (!geq_margin(ev.duration, SONY_BIT_SPACE, SONY_UNIT / 2))
+ if (!geq_margin(ev.val, SONY_BIT_SPACE, SONY_UNIT / 2))
break;
decrease_duration(&ev, SONY_BIT_SPACE);
- if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) {
+ if (!geq_margin(ev.val, SONY_UNIT, SONY_UNIT / 2)) {
data->state = STATE_BIT_PULSE;
return 0;
}
@@ -117,10 +119,10 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
/* Fall through */
case STATE_FINISHED:
- if (ev.pulse)
+ if (is_pulse(ev))
break;
- if (!geq_margin(ev.duration, SONY_TRAILER_SPACE, SONY_UNIT / 2))
+ if (!geq_margin(ev.val, SONY_TRAILER_SPACE, SONY_UNIT / 2))
break;
switch (data->count) {
@@ -158,7 +160,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
out:
IR_dprintk(1, "Sony decode failed at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, TO_US(ev.val), TO_STR(ev.code));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 51fb845..dcef9e5 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -190,16 +190,15 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int
size = length << 3;
next_one = find_next_bit_le(ldata, size, 0);
if (next_one > 0) {
- ev.pulse = true;
- ev.duration =
- ITE_BITS_TO_NS(next_one, sample_period);
+ ev.code = RC_IR_RAW_PULSE;
+ ev.val = ITE_BITS_TO_NS(next_one, sample_period);
ir_raw_event_store_with_filter(dev->rdev, &ev);
}
while (next_one < size) {
next_zero = find_next_zero_bit_le(ldata, size, next_one + 1);
- ev.pulse = false;
- ev.duration = ITE_BITS_TO_NS(next_zero - next_one, sample_period);
+ ev.code = RC_IR_RAW_SPACE;
+ ev.val = ITE_BITS_TO_NS(next_zero - next_one, sample_period);
ir_raw_event_store_with_filter(dev->rdev, &ev);
if (next_zero < size) {
@@ -207,12 +206,10 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int
find_next_bit_le(ldata,
size,
next_zero + 1);
- ev.pulse = true;
- ev.duration =
- ITE_BITS_TO_NS(next_one - next_zero,
- sample_period);
- ir_raw_event_store_with_filter
- (dev->rdev, &ev);
+ ev.code = RC_IR_RAW_PULSE;
+ ev.val = ITE_BITS_TO_NS(next_one - next_zero,
+ sample_period);
+ ir_raw_event_store_with_filter(dev->rdev, &ev);
} else
next_one = size;
}
diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h
index aa899a0..5c1fa57 100644
--- a/drivers/media/rc/ite-cir.h
+++ b/drivers/media/rc/ite-cir.h
@@ -125,7 +125,7 @@ struct ite_dev_params {
struct ite_dev {
struct pnp_dev *pdev;
struct rc_dev *rdev;
- struct ir_raw_event rawir;
+ struct rc_event rawir;
/* sync data */
spinlock_t lock;
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 952ea01..4652c11 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -959,13 +959,16 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
case PARSE_IRDATA:
ir->rem--;
init_ir_raw_event(&rawir);
- rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
- rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
- * US_TO_NS(MCE_TIME_UNIT);
+ if (ir->buf_in[i] & MCE_PULSE_BIT)
+ rawir.code = RC_IR_RAW_PULSE;
+ else
+ rawir.code = RC_IR_RAW_SPACE;
+ rawir.val = (ir->buf_in[i] & MCE_PULSE_MASK) *
+ US_TO_NS(MCE_TIME_UNIT);
- mce_dbg(ir->dev, "Storing %s with duration %d\n",
- rawir.pulse ? "pulse" : "space",
- rawir.duration);
+ mce_dbg(ir->dev, "Storing %s with duration %llu\n",
+ rawir.code == RC_IR_RAW_PULSE ? "pulse" : "space",
+ (long long unsigned)rawir.val);
ir_raw_event_store_with_filter(ir->rc, &rawir);
break;
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 4c37ade..aae1a09 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -612,7 +612,7 @@ static void nvt_dump_rx_buf(struct nvt_dev *nvt)
*/
static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
{
- DEFINE_IR_RAW_EVENT(rawir);
+ DEFINE_IR_RAW_EVENT(ev);
u32 carrier;
u8 sample;
int i;
@@ -627,19 +627,19 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
nvt_dbg_verbose("Processing buffer of len %d", nvt->pkts);
- init_ir_raw_event(&rawir);
-
for (i = 0; i < nvt->pkts; i++) {
sample = nvt->buf[i];
- rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
- rawir.duration = US_TO_NS((sample & BUF_LEN_MASK)
- * SAMPLE_PERIOD);
+ ev.code = RC_IR_RAW_SPACE;
+ if (sample & BUF_PULSE_BIT)
+ ev.code = RC_IR_RAW_PULSE;
+ ev.val = US_TO_NS((sample & BUF_LEN_MASK) * SAMPLE_PERIOD);
- nvt_dbg("Storing %s with duration %d",
- rawir.pulse ? "pulse" : "space", rawir.duration);
+ nvt_dbg("Storing %s with duration %llu",
+ ev.code == RC_IR_RAW_PULSE ? "pulse" : "space",
+ (long long unsigned)ev.val);
- ir_raw_event_store_with_filter(nvt->rdev, &rawir);
+ ir_raw_event_store_with_filter(nvt->rdev, &ev);
/*
* BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 54af19a..376030e 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -26,7 +26,7 @@ struct ir_raw_handler {
struct list_head list;
unsigned protocols; /* which are handled by this handler */
- int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
+ int (*decode)(struct rc_dev *dev, struct rc_event event);
/* These two should only be used by the lirc decoder */
int (*raw_register)(struct rc_dev *dev);
@@ -39,14 +39,14 @@ struct ir_raw_handler {
struct ir_raw_event_ctrl {
struct list_head list; /* to keep track of raw clients */
struct task_struct *thread;
- DECLARE_KFIFO(kfifo, struct ir_raw_event, RC_MAX_IR_EVENTS); /* for pulse/space durations */
+ DECLARE_KFIFO(kfifo, struct rc_event, RC_MAX_IR_EVENTS); /* for pulse/space durations */
ktime_t last_event; /* when last event occurred */
enum raw_event_type last_type; /* last event type */
struct rc_dev *dev; /* pointer to the parent rc_dev */
/* raw decoder state follows */
- struct ir_raw_event prev_ev;
- struct ir_raw_event this_ev;
+ struct rc_event prev_ev;
+ struct rc_event this_ev;
struct nec_dec {
int state;
unsigned count;
@@ -121,27 +121,28 @@ static inline bool eq_margin(unsigned d1, unsigned d2, unsigned margin)
return ((d1 > (d2 - margin)) && (d1 < (d2 + margin)));
}
-static inline bool is_transition(struct ir_raw_event *x, struct ir_raw_event *y)
+static inline bool is_transition(struct rc_event *x, struct rc_event *y)
{
- return x->pulse != y->pulse;
+ return x->code != y->code;
}
-static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration)
+static inline void decrease_duration(struct rc_event *ev, unsigned duration)
{
- if (duration > ev->duration)
- ev->duration = 0;
- else
- ev->duration -= duration;
+ ev->val -= min_t(u64, ev->val, duration);
}
-/* Returns true if event is normal pulse/space event */
-static inline bool is_timing_event(struct ir_raw_event ev)
+static inline bool is_pulse(struct rc_event ev)
{
- return !ev.carrier_report && !ev.reset;
+ return ev.code == RC_IR_RAW_PULSE;
}
-#define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000)
-#define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space")
+static inline bool is_space(struct rc_event ev)
+{
+ return ev.code == RC_IR_RAW_SPACE;
+}
+
+#define TO_US(duration) ((unsigned)DIV_ROUND_CLOSEST((duration), 1000))
+#define TO_STR(code) ((code == RC_IR_RAW_PULSE) ? "pulse" : "space")
/*
* Routines from rc-raw.c to be used internally and by decoders
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index e6a6eea..6a60ad6 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -33,12 +33,12 @@ static atomic_t available_protocols = ATOMIC_INIT(0);
static int ir_raw_event_thread(void *data)
{
- struct ir_raw_event ev;
+ struct rc_event ev;
struct ir_raw_handler *handler;
struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
while (!kthread_should_stop()) {
- if (kfifo_out(&raw->kfifo, &ev, 1) == 0) {
+ if (!kfifo_get(&raw->kfifo, &ev)) {
set_current_state(TASK_INTERRUPTIBLE);
schedule();
continue;
@@ -57,36 +57,29 @@ static int ir_raw_event_thread(void *data)
/**
* ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
* @dev: the struct rc_dev device descriptor
- * @ev: the struct ir_raw_event descriptor of the pulse/space
+ * @ev: the struct rc_event descriptor of the event
*
- * This routine (which may be called from an interrupt context) stores a
- * pulse/space duration for the raw ir decoding state machines. Pulses are
- * signalled as positive values and spaces as negative values. A zero value
- * will reset the decoding state machines. Drivers are responsible for
- * synchronizing calls to this function.
+ * This routine (which may be called from an interrupt context) stores an
+ * event for the raw ir decoding state machines and interested userspace
+ * processes.
+ *
+ * Drivers are responsible for synchronizing calls to this function.
*/
-int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
+int ir_raw_event_store(struct rc_dev *dev, struct rc_event *ev)
{
if (!dev->raw)
return -EINVAL;
- IR_dprintk(2, "sample: (%05dus %s)\n",
- TO_US(ev->duration), TO_STR(ev->pulse));
-
- if (ev->reset)
- rc_event(dev, RC_IR_RAW, RC_IR_RAW_RESET, 1);
- else if (ev->carrier_report)
- rc_event(dev, RC_IR_RAW, RC_IR_RAW_CARRIER, ev->carrier);
- else if (ev->timeout)
- rc_event(dev, RC_IR_RAW, RC_IR_RAW_STOP, 1);
- else if (ev->pulse)
- rc_event(dev, RC_IR_RAW, RC_IR_RAW_PULSE, ev->duration);
- else
- rc_event(dev, RC_IR_RAW, RC_IR_RAW_SPACE, ev->duration);
+ if (ev->type != RC_IR_RAW)
+ return -EINVAL;
+
+ if (ev->reserved)
+ return -EINVAL;
- if (kfifo_in(&dev->raw->kfifo, ev, 1) != 1)
+ if (!kfifo_put(&dev->raw->kfifo, ev))
return -ENOMEM;
+ rc_event(dev, ev->type, ev->code, ev->val);
return 0;
}
EXPORT_SYMBOL_GPL(ir_raw_event_store);
@@ -122,15 +115,15 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
if (delta > MS_TO_NS(500) || !dev->raw->last_type)
type |= IR_START_EVENT;
else
- ev.duration = delta;
+ ev.val = delta;
if (type & IR_START_EVENT)
ir_raw_event_reset(dev);
else if (dev->raw->last_type & IR_SPACE) {
- ev.pulse = false;
+ ev.code = RC_IR_RAW_SPACE;
rc = ir_raw_event_store(dev, &ev);
} else if (dev->raw->last_type & IR_PULSE) {
- ev.pulse = true;
+ ev.code = RC_IR_RAW_PULSE;
rc = ir_raw_event_store(dev, &ev);
} else
return 0;
@@ -144,36 +137,42 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
/**
* ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing
* @dev: the struct rc_dev device descriptor
- * @type: the type of the event that has occurred
+ * @ev: the struct rc_event descriptor of the event
*
* This routine (which may be called from an interrupt context) works
* in similar manner to ir_raw_event_store_edge.
* This routine is intended for devices with limited internal buffer
* It automerges samples of same type, and handles timeouts
*/
-int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
+int ir_raw_event_store_with_filter(struct rc_dev *dev, struct rc_event *ev)
{
if (!dev->raw)
return -EINVAL;
/* Ignore spaces in idle mode */
- if (dev->idle && !ev->pulse)
- return 0;
- else if (dev->idle)
+ if (dev->idle) {
+ if (ev->code == RC_IR_RAW_SPACE)
+ return 0;
ir_raw_event_set_idle(dev, false);
+ }
- if (!dev->raw->this_ev.duration)
+ if (!is_ir_raw_timing_event(*ev)) {
+ ir_raw_event_store(dev, &dev->raw->this_ev);
+ return 0;
+ }
+
+ if (!dev->raw->this_ev.val)
dev->raw->this_ev = *ev;
- else if (ev->pulse == dev->raw->this_ev.pulse)
- dev->raw->this_ev.duration += ev->duration;
+ else if (ev->code == dev->raw->this_ev.code)
+ dev->raw->this_ev.val += ev->val;
else {
ir_raw_event_store(dev, &dev->raw->this_ev);
dev->raw->this_ev = *ev;
}
/* Enter idle mode if nessesary */
- if (!ev->pulse && dev->timeout &&
- dev->raw->this_ev.duration >= dev->timeout)
+ if (ev->code == RC_IR_RAW_SPACE && dev->timeout &&
+ dev->raw->this_ev.val >= dev->timeout)
ir_raw_event_set_idle(dev, true);
return 0;
@@ -187,17 +186,30 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
*/
void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
{
+ DEFINE_IR_RAW_EVENT(ev);
+
if (!dev->raw)
return;
+ if (dev->idle == idle)
+ return;
+
IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
+
if (idle) {
- dev->raw->this_ev.timeout = true;
- ir_raw_event_store(dev, &dev->raw->this_ev);
- init_ir_raw_event(&dev->raw->this_ev);
+ if (dev->raw->this_ev.val > 0)
+ ir_raw_event_store(dev, &dev->raw->this_ev);
+ ev.code = RC_IR_RAW_STOP;
+ ev.val = 1;
+ } else {
+ ev.code = RC_IR_RAW_START;
+ ev.val = 1;
}
+ init_ir_raw_event(&dev->raw->this_ev);
+ ir_raw_event_store(dev, &ev);
+
if (dev->s_idle)
dev->s_idle(dev, idle);
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 45ef966..f0e6e35 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -53,8 +53,7 @@ static int loop_tx_ir(struct rc_dev *dev)
{
struct loopback_dev *lodev = dev->priv;
u32 rxmask;
- struct rc_event event;
- DEFINE_IR_RAW_EVENT(rawir);
+ struct rc_event ev;
if (lodev->txcarrier < lodev->rxcarriermin ||
lodev->txcarrier > lodev->rxcarriermax) {
@@ -74,21 +73,17 @@ static int loop_tx_ir(struct rc_dev *dev)
return 0;
}
- while (kfifo_get(&dev->txfifo, &event)) {
- if (is_ir_raw_timing_event(event))
+ while (kfifo_get(&dev->txfifo, &ev)) {
+ if (!is_ir_raw_timing_event(ev))
continue;
- init_ir_raw_event(&rawir);
- rawir.duration = event.val;
- if (event.code == RC_IR_RAW_PULSE)
- rawir.pulse = true;
- ir_raw_event_store_with_filter(dev, &rawir);
+ ir_raw_event_store_with_filter(dev, &ev);
}
/* Fake a silence long enough to cause us to go idle */
- init_ir_raw_event(&rawir);
- rawir.pulse = false;
- rawir.duration = dev->timeout;
- ir_raw_event_store_with_filter(dev, &rawir);
+ init_ir_raw_event(&ev);
+ ev.code = RC_IR_RAW_SPACE;
+ ev.val = dev->timeout;
+ ir_raw_event_store_with_filter(dev, &ev);
ir_raw_event_handle(dev);
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 760f13e..548603b 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -414,7 +414,7 @@ static void redrat3_rx_timeout(unsigned long data)
static void redrat3_process_ir_data(struct redrat3_dev *rr3)
{
- DEFINE_IR_RAW_EVENT(rawir);
+ DEFINE_IR_RAW_EVENT(ev);
struct redrat3_signal_header header;
struct device *dev;
int i, trailer = 0;
@@ -488,34 +488,27 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
single_len = redrat3_len_to_us((u32)be16_to_cpu(val));
/* we should always get pulse/space/pulse/space samples */
- if (i % 2)
- rawir.pulse = false;
- else
- rawir.pulse = true;
+ ev.code = i % 2 ? RC_IR_RAW_SPACE : RC_IR_RAW_PULSE;
+ ev.val = min_t(u64, IR_MAX_DURATION, US_TO_NS(single_len));
- rawir.duration = US_TO_NS(single_len);
/* Save initial pulse length to fudge trailer */
if (i == 0)
- trailer = rawir.duration;
- /* cap the value to IR_MAX_DURATION */
- rawir.duration &= IR_MAX_DURATION;
+ trailer = single_len;
- rr3_dbg(dev, "storing %s with duration %d (i: %d)\n",
- rawir.pulse ? "pulse" : "space", rawir.duration, i);
- ir_raw_event_store_with_filter(rr3->rc, &rawir);
+ rr3_dbg(dev, "storing %s with duration %llu (i: %d)\n",
+ ev.code == RC_IR_RAW_PULSE ? "pulse" : "space",
+ (long long unsigned)ev.val, i);
+ ir_raw_event_store_with_filter(rr3->rc, &ev);
}
/* add a trailing space, if need be */
if (i % 2) {
- rawir.pulse = false;
+ ev.code = RC_IR_RAW_SPACE;
/* this duration is made up, and may not be ideal... */
- if (trailer < US_TO_NS(1000))
- rawir.duration = US_TO_NS(2800);
- else
- rawir.duration = trailer;
- rr3_dbg(dev, "storing trailing space with duration %d\n",
- rawir.duration);
- ir_raw_event_store_with_filter(rr3->rc, &rawir);
+ ev.val = US_TO_NS(trailer < 1000 ? 2800 : trailer);
+ rr3_dbg(dev, "storing trailing space with duration %llu\n",
+ (long long unsigned)ev.val);
+ ir_raw_event_store_with_filter(rr3->rc, &ev);
}
rr3_dbg(dev, "calling ir_raw_event_handle\n");
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index 4156197..9049383 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -129,17 +129,18 @@ static struct usb_driver streamzap_driver = {
.id_table = streamzap_table,
};
-static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
+static void sz_push(struct streamzap_ir *sz, struct rc_event ev)
{
dev_dbg(sz->dev, "Storing %s with duration %u us\n",
- (rawir.pulse ? "pulse" : "space"), rawir.duration);
- ir_raw_event_store_with_filter(sz->rdev, &rawir);
+ (ev.code == RC_IR_RAW_PULSE ? "pulse" : "space"),
+ (unsigned)(ev.val / 1000));
+ ir_raw_event_store_with_filter(sz->rdev, &ev);
}
static void sz_push_full_pulse(struct streamzap_ir *sz,
unsigned char value)
{
- DEFINE_IR_RAW_EVENT(rawir);
+ DEFINE_IR_RAW_EVENT(ev);
if (sz->idle) {
long deltv;
@@ -148,31 +149,29 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
do_gettimeofday(&sz->signal_start);
deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec;
- rawir.pulse = false;
+ ev.code = RC_IR_RAW_SPACE;
if (deltv > 15) {
/* really long time */
- rawir.duration = IR_MAX_DURATION;
+ ev.val = IR_MAX_DURATION;
} else {
- rawir.duration = (int)(deltv * 1000000 +
- sz->signal_start.tv_usec -
- sz->signal_last.tv_usec);
- rawir.duration -= sz->sum;
- rawir.duration = US_TO_NS(rawir.duration);
- rawir.duration &= IR_MAX_DURATION;
+ ev.val = (deltv * 1000000 +
+ sz->signal_start.tv_usec -
+ sz->signal_last.tv_usec);
+ ev.val -= sz->sum;
+ ev.val = min_t(u64, US_TO_NS(ev.val), IR_MAX_DURATION);
}
- sz_push(sz, rawir);
+ sz_push(sz, ev);
sz->idle = false;
sz->sum = 0;
}
- rawir.pulse = true;
- rawir.duration = ((int) value) * SZ_RESOLUTION;
- rawir.duration += SZ_RESOLUTION / 2;
- sz->sum += rawir.duration;
- rawir.duration = US_TO_NS(rawir.duration);
- rawir.duration &= IR_MAX_DURATION;
- sz_push(sz, rawir);
+ ev.code = RC_IR_RAW_PULSE;
+ ev.val = value * SZ_RESOLUTION;
+ ev.val += SZ_RESOLUTION / 2;
+ sz->sum += ev.val;
+ ev.val = min_t(u64, US_TO_NS(ev.val), IR_MAX_DURATION);
+ sz_push(sz, ev);
}
static void sz_push_half_pulse(struct streamzap_ir *sz,
@@ -184,14 +183,13 @@ static void sz_push_half_pulse(struct streamzap_ir *sz,
static void sz_push_full_space(struct streamzap_ir *sz,
unsigned char value)
{
- DEFINE_IR_RAW_EVENT(rawir);
-
- rawir.pulse = false;
- rawir.duration = ((int) value) * SZ_RESOLUTION;
- rawir.duration += SZ_RESOLUTION / 2;
- sz->sum += rawir.duration;
- rawir.duration = US_TO_NS(rawir.duration);
- sz_push(sz, rawir);
+ DEFINE_IR_RAW_EVENT(ev);
+
+ ev.code = RC_IR_RAW_SPACE;
+ ev.val = value * SZ_RESOLUTION + SZ_RESOLUTION / 2;
+ sz->sum += ev.val;
+ ev.val = US_TO_NS(ev.val);
+ sz_push(sz, ev);
}
static void sz_push_half_space(struct streamzap_ir *sz,
@@ -258,13 +256,13 @@ static void streamzap_callback(struct urb *urb)
break;
case FullSpace:
if (sz->buf_in[i] == SZ_TIMEOUT) {
- DEFINE_IR_RAW_EVENT(rawir);
+ DEFINE_IR_RAW_EVENT(ev);
- rawir.pulse = false;
- rawir.duration = sz->rdev->timeout;
+ ev.code = RC_IR_RAW_STOP;
+ ev.val = 1;
sz->idle = true;
if (sz->timeout_enabled)
- sz_push(sz, rawir);
+ sz_push(sz, ev);
ir_raw_event_handle(sz->rdev);
ir_raw_event_reset(sz->rdev);
} else {
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 76a8104..d141f8e 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -208,7 +208,6 @@ struct wbcir_data {
/* RX state */
enum wbcir_rxstate rxstate;
struct led_trigger *rxtrigger;
- struct ir_raw_event rxev;
/* TX state */
enum wbcir_txstate txstate;
@@ -355,8 +354,8 @@ wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device)
irdata = inb(data->sbase + WBCIR_REG_SP3_RXDATA);
if (data->rxstate == WBCIR_RXSTATE_ERROR)
continue;
- rawir.pulse = irdata & 0x80 ? false : true;
- rawir.duration = US_TO_NS((irdata & 0x7F) * 10);
+ rawir.code = irdata & 0x80 ? RC_IR_RAW_SPACE : RC_IR_RAW_PULSE;
+ rawir.val = US_TO_NS((irdata & 0x7F) * 10);
ir_raw_event_store_with_filter(data->dev, &rawir);
}
@@ -917,9 +916,7 @@ wbcir_init_hw(struct wbcir_data *data)
/* Clear RX state */
data->rxstate = WBCIR_RXSTATE_INACTIVE;
- data->rxev.duration = 0;
ir_raw_event_reset(data->dev);
- ir_raw_event_handle(data->dev);
/*
* Check TX state, if we did a suspend/resume cycle while TX was
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
index dbf0d34..fb41795 100644
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -51,18 +51,17 @@ static void cx23885_input_process_measurements(struct cx23885_dev *dev,
ssize_t num;
int count, i;
bool handle = false;
- struct ir_raw_event ir_core_event[64];
+ struct rc_event ev[64];
do {
num = 0;
- v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ir_core_event,
- sizeof(ir_core_event), &num);
+ v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *)ev,
+ sizeof(rc_event), &num);
- count = num / sizeof(struct ir_raw_event);
+ count = num / sizeof(struct rc_event);
for (i = 0; i < count; i++) {
- ir_raw_event_store(kernel_ir->rc,
- &ir_core_event[i]);
+ ir_raw_event_store(kernel_ir->rc, &ev[i]);
handle = true;
}
} while (num != 0);
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c
index f3609a2..2e6ffe8 100644
--- a/drivers/media/video/cx23885/cx23888-ir.c
+++ b/drivers/media/video/cx23885/cx23888-ir.c
@@ -116,12 +116,12 @@ MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]");
/*
* We use this union internally for convenience, but callers to tx_write
- * and rx_read will be expecting records of type struct ir_raw_event.
- * Always ensure the size of this union is dictated by struct ir_raw_event.
+ * and rx_read will be expecting records of type struct rc_event.
+ * Always ensure the size of this union is dictated by struct rc_event.
*/
union cx23888_ir_fifo_rec {
u32 hw_fifo_data;
- struct ir_raw_event ir_core_data;
+ struct rc_event ir_core_data;
};
#define CX23888_IR_RX_KFIFO_SIZE (256 * sizeof(union cx23888_ir_fifo_rec))
@@ -662,57 +662,62 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
}
/* Receiver */
-static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
- ssize_t *num)
+static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t bufsize,
+ ssize_t *bytes_read)
{
struct cx23888_ir_state *state = to_state(sd);
- bool invert = (bool) atomic_read(&state->rx_invert);
- u16 divider = (u16) atomic_read(&state->rxclk_divider);
-
- unsigned int i, n;
- union cx23888_ir_fifo_rec *p;
- unsigned u, v, w;
-
- n = count / sizeof(union cx23888_ir_fifo_rec)
- * sizeof(union cx23888_ir_fifo_rec);
- if (n == 0) {
- *num = 0;
- return 0;
- }
-
- n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock);
-
- n /= sizeof(union cx23888_ir_fifo_rec);
- *num = n * sizeof(union cx23888_ir_fifo_rec);
-
- for (p = (union cx23888_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) {
+ bool invert = (bool)atomic_read(&state->rx_invert);
+ u16 divider = (u16)atomic_read(&state->rxclk_divider);
+ struct rc_event *ev = (struct rc_event *)buf;
+ union cx23888_ir_fifo_rec rec;
+ unsigned max_events;
+ unsigned events = 0;
+ bool pulse, timeout;
+ u64 val;
+
+ max_events = bufsize / sizeof(union cx23888_ir_fifo_rec);
+
+ while (events + 2 <= max_events) {
+ if (kfifo_out_spinlocked(&state->rx_kfifo, &rec, sizeof(rec),
+ &state->rx_kfifo_lock) != sizeof(rec))
+ break;
- if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
+ if (rec.hw_fifo_data & FIFO_RXTX_RTO) {
/* Assume RTO was because of no IR light input */
- u = 0;
- w = 1;
+ pulse = false;
+ timeout = true;
} else {
- u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
+ pulse = (rec.hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
if (invert)
- u = u ? 0 : 1;
- w = 0;
+ pulse = !pulse;
+ timeout = false;
}
- v = (unsigned) pulse_width_count_to_ns(
- (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
- if (v > IR_MAX_DURATION)
- v = IR_MAX_DURATION;
-
- init_ir_raw_event(&p->ir_core_data);
- p->ir_core_data.pulse = u;
- p->ir_core_data.duration = v;
- p->ir_core_data.timeout = w;
+ val = min_t(u64, IR_MAX_DURATION,
+ pulse_width_count_to_ns(rec.hw_fifo_data & FIFO_RXTX,
+ divider));
+
+ if (val) {
+ init_ir_raw_event(ev);
+ ev->code = pulse ? RC_IR_RAW_PULSE : RC_IR_RAW_SPACE;
+ ev->val = val;
+ events++;
+ ev++;
+ v4l2_dbg(2, ir_888_debug, sd, "rx read: %10llu ns %s\n",
+ (long long unsigned)val, pulse ? "pulse" : "space");
+ }
- v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns %s %s\n",
- v, u ? "mark" : "space", w ? "(timed out)" : "");
- if (w)
+ if (timeout) {
+ init_ir_raw_event(ev);
+ ev->code = RC_IR_RAW_STOP;
+ ev->val = 1;
+ events++;
+ ev++;
v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n");
+ }
}
+
+ *bytes_read = events * sizeof(union cx23888_ir_fifo_rec);
return 0;
}
diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/video/cx25840/cx25840-ir.c
index cd3aca7..101d150 100644
--- a/drivers/media/video/cx25840/cx25840-ir.c
+++ b/drivers/media/video/cx25840/cx25840-ir.c
@@ -98,12 +98,12 @@ MODULE_PARM_DESC(ir_debug, "enable integrated IR debug messages");
/*
* We use this union internally for convenience, but callers to tx_write
- * and rx_read will be expecting records of type struct ir_raw_event.
- * Always ensure the size of this union is dictated by struct ir_raw_event.
+ * and rx_read will be expecting records of type struct rc_event.
+ * Always ensure the size of this union is dictated by struct rc_event.
*/
union cx25840_ir_fifo_rec {
u32 hw_fifo_data;
- struct ir_raw_event ir_core_data;
+ struct rc_event ir_core_data;
};
#define CX25840_IR_RX_KFIFO_SIZE (256 * sizeof(union cx25840_ir_fifo_rec))
@@ -659,63 +659,67 @@ int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled)
}
/* Receiver */
-static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
- ssize_t *num)
+static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t bufsize,
+ ssize_t *bytes_read)
{
- struct cx25840_ir_state *ir_state = to_ir_state(sd);
+ struct cx25840_ir_state *state = to_ir_state(sd);
bool invert;
u16 divider;
- unsigned int i, n;
- union cx25840_ir_fifo_rec *p;
- unsigned u, v, w;
-
- if (ir_state == NULL)
+ struct rc_event *ev = (struct rc_event *)buf;
+ union cx25840_ir_fifo_rec rec;
+ unsigned max_events;
+ unsigned events = 0;
+ bool pulse, timeout;
+ u64 val;
+
+ if (!state)
return -ENODEV;
- invert = (bool) atomic_read(&ir_state->rx_invert);
- divider = (u16) atomic_read(&ir_state->rxclk_divider);
-
- n = count / sizeof(union cx25840_ir_fifo_rec)
- * sizeof(union cx25840_ir_fifo_rec);
- if (n == 0) {
- *num = 0;
- return 0;
- }
-
- n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n,
- &ir_state->rx_kfifo_lock);
+ invert = (bool)atomic_read(&state->rx_invert);
+ divider = (u16)atomic_read(&state->rxclk_divider);
+ max_events = bufsize / sizeof(union cx25840_ir_fifo_rec);
- n /= sizeof(union cx25840_ir_fifo_rec);
- *num = n * sizeof(union cx25840_ir_fifo_rec);
-
- for (p = (union cx25840_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) {
+ while (events + 2 <= max_events) {
+ if (kfifo_out_spinlocked(&state->rx_kfifo, &rec, sizeof(rec),
+ &state->rx_kfifo_lock) != sizeof(rec))
+ break;
- if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
+ if (rec.hw_fifo_data & FIFO_RXTX_RTO) {
/* Assume RTO was because of no IR light input */
- u = 0;
- w = 1;
+ pulse = false;
+ timeout = true;
} else {
- u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
+ pulse = (rec.hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
if (invert)
- u = u ? 0 : 1;
- w = 0;
+ pulse = !pulse;
+ timeout = false;
}
- v = (unsigned) pulse_width_count_to_ns(
- (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
- if (v > IR_MAX_DURATION)
- v = IR_MAX_DURATION;
-
- init_ir_raw_event(&p->ir_core_data);
- p->ir_core_data.pulse = u;
- p->ir_core_data.duration = v;
- p->ir_core_data.timeout = w;
+ val = min_t(u64, IR_MAX_DURATION,
+ pulse_width_count_to_ns(rec.hw_fifo_data & FIFO_RXTX,
+ divider));
+
+ if (val) {
+ init_ir_raw_event(ev);
+ ev->code = pulse ? RC_IR_RAW_PULSE : RC_IR_RAW_SPACE;
+ ev->val = val;
+ events++;
+ ev++;
+ v4l2_dbg(2, ir_debug, sd, "rx read: %10llu ns %s\n",
+ (long long unsigned)val, pulse ? "pulse" : "space");
+ }
- v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s %s\n",
- v, u ? "mark" : "space", w ? "(timed out)" : "");
- if (w)
+ if (timeout) {
+ init_ir_raw_event(ev);
+ ev->code = RC_IR_RAW_STOP;
+ ev->val = 1;
+ events++;
+ ev++;
v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n");
+ }
}
+
+ *bytes_read = events * sizeof(union cx25840_ir_fifo_rec);
return 0;
}
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 158c1b6..befc2e1 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -510,7 +510,7 @@ void cx88_ir_irq(struct cx88_core *core)
struct cx88_IR *ir = core->ir;
u32 samples;
unsigned todo, bits;
- struct ir_raw_event ev;
+ DEFINE_IR_RAW_EVENT(ev);
if (!ir || !ir->sampling)
return;
@@ -527,9 +527,14 @@ void cx88_ir_irq(struct cx88_core *core)
init_ir_raw_event(&ev);
for (todo = 32; todo > 0; todo -= bits) {
- ev.pulse = samples & 0x80000000 ? false : true;
- bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples));
- ev.duration = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate;
+ if (samples & 0x80000000) {
+ ev.code = RC_IR_RAW_PULSE;
+ bits = min(todo, 32U - fls(samples));
+ } else {
+ ev.code = RC_IR_RAW_SPACE;
+ bits = min(todo, 32U - fls(~samples));
+ }
+ ev.val = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate;
ir_raw_event_store_with_filter(ir->dev, &ev);
samples <<= bits;
}
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index d8cad87..ea3dcf4 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -199,22 +199,6 @@ struct rc_keymap_entry {
};
};
-struct ir_raw_event {
- union {
- u32 duration;
-
- struct {
- u32 carrier;
- u8 duty_cycle;
- };
- };
-
- unsigned pulse:1;
- unsigned reset:1;
- unsigned timeout:1;
- unsigned carrier_report:1;
-};
-
/**
* struct rc_event - used to communicate rc events to userspace
* @type: the event type
diff --git a/include/media/rc-ir-raw.h b/include/media/rc-ir-raw.h
index 7fd0693..4521d95 100644
--- a/include/media/rc-ir-raw.h
+++ b/include/media/rc-ir-raw.h
@@ -29,17 +29,19 @@ enum raw_event_type {
IR_STOP_EVENT = (1 << 3),
};
-#define DEFINE_IR_RAW_EVENT(event) \
- struct ir_raw_event event = { \
- { .duration = 0 } , \
- .pulse = 0, \
- .reset = 0, \
- .timeout = 0, \
- .carrier_report = 0 }
+#define DEFINE_IR_RAW_EVENT(ev) \
+ struct rc_event ev = { \
+ .type = RC_IR_RAW, \
+ .code = RC_IR_RAW_PULSE, \
+ .reserved = 0, \
+ .val = 0 }
-static inline void init_ir_raw_event(struct ir_raw_event *ev)
+static inline void init_ir_raw_event(struct rc_event *ev)
{
- memset(ev, 0, sizeof(*ev));
+ ev->type = RC_IR_RAW;
+ ev->code = RC_IR_RAW_PULSE;
+ ev->reserved = 0;
+ ev->val = 0;
}
#define IR_MAX_DURATION 0xFFFFFFFF /* a bit more than 4 seconds */
@@ -48,19 +50,21 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev)
#define MS_TO_NS(msec) ((msec) * 1000 * 1000)
void ir_raw_event_handle(struct rc_dev *dev);
-int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
+int ir_raw_event_store(struct rc_dev *dev, struct rc_event *ev);
int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
-int ir_raw_event_store_with_filter(struct rc_dev *dev,
- struct ir_raw_event *ev);
+int ir_raw_event_store_with_filter(struct rc_dev *dev, struct rc_event *ev);
void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
int rc_register_ir_raw_device(struct rc_dev *dev);
void rc_unregister_ir_raw_device(struct rc_dev *dev);
static inline void ir_raw_event_reset(struct rc_dev *dev)
{
- DEFINE_IR_RAW_EVENT(ev);
- ev.reset = true;
-
+ struct rc_event ev = {
+ .type = RC_IR_RAW,
+ .code = RC_IR_RAW_RESET,
+ .reserved = 0,
+ .val = 1
+ };
ir_raw_event_store(dev, &ev);
ir_raw_event_handle(dev);
}
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 41/43] rc-core: add keytable events
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (39 preceding siblings ...)
2012-05-23 9:45 ` [PATCH 40/43] rc-core: use struct rc_event for all rc communication David Härdeman
@ 2012-05-23 9:45 ` David Härdeman
2012-05-23 9:45 ` [PATCH 42/43] rc-core: move remaining keytable functions David Härdeman
` (2 subsequent siblings)
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:45 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Add separe rc device events on keytable addition/removal.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-main.c | 2 ++
include/media/rc-core.h | 2 ++
2 files changed, 4 insertions(+)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 6c8bc3a..b16dbf4 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -513,6 +513,7 @@ static int rc_add_keytable(struct rc_dev *dev, const char *name,
rcu_assign_pointer(dev->keytables[i], kt);
list_add_rcu(&kt->node, &dev->keytable_list);
synchronize_rcu();
+ rc_event(dev, RC_CORE, RC_CORE_KT_ADDED, i);
return 0;
}
@@ -530,6 +531,7 @@ static int rc_remove_keytable(struct rc_dev *dev, unsigned i)
return -EINVAL;
rc_keytable_destroy(kt);
+ rc_event(dev, RC_CORE, RC_CORE_KT_REMOVED, i);
return 0;
}
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index ea3dcf4..056275a 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -221,6 +221,8 @@ struct rc_event {
/* RC_CORE codes */
#define RC_CORE_DROPPED 0x0
+#define RC_CORE_KT_ADDED 0x1
+#define RC_CORE_KT_REMOVED 0x2
/* RC_KEY codes */
#define RC_KEY_REPEAT 0x0
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 42/43] rc-core: move remaining keytable functions
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (40 preceding siblings ...)
2012-05-23 9:45 ` [PATCH 41/43] rc-core: add keytable events David Härdeman
@ 2012-05-23 9:45 ` David Härdeman
2012-05-23 9:45 ` [PATCH 43/43] rc-core: make rc-core.h userspace friendly David Härdeman
2012-06-22 17:37 ` [PATCH 00/43] rc-core: feature parity with LIRC Mauro Carvalho Chehab
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:45 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
Move some more keytable related functionality over to rc-keytable.c which
allows more implementational details to be obscured away.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
drivers/media/rc/rc-core-priv.h | 11 +-
drivers/media/rc/rc-keytable.c | 213 +++++++++++++++++++++++++++++++++------
drivers/media/rc/rc-main.c | 132 +-----------------------
include/media/rc-core.h | 44 --------
4 files changed, 193 insertions(+), 207 deletions(-)
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 376030e..3f056e3 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -156,13 +156,10 @@ void ir_raw_init(void);
/*
* Methods from rc-keytable.c to be used internally
*/
-void rc_keytable_keyup(struct rc_keytable *kt);
-void rc_keytable_repeat(struct rc_keytable *kt);
-void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
- u64 scancode, u8 toggle, bool autokeyup);
-struct rc_keytable *rc_keytable_create(struct rc_dev *dev, const char *name,
- const char *map_name);
-void rc_keytable_destroy(struct rc_keytable *kt);
+int rc_keytable_add(struct rc_dev *dev, const char *name, const char *map_name);
+int rc_keytable_remove(struct rc_dev *dev, unsigned i);
+int rc_keytable_get_name(struct rc_dev *dev, unsigned i,
+ char *buf, size_t bufsize);
/* Only to be used by rc-core and ir-lirc-codec */
void rc_init_ir_rx(struct rc_dev *dev, struct rc_ir_rx *rx);
diff --git a/drivers/media/rc/rc-keytable.c b/drivers/media/rc/rc-keytable.c
index d0777cb..027a703 100644
--- a/drivers/media/rc/rc-keytable.c
+++ b/drivers/media/rc/rc-keytable.c
@@ -29,6 +29,50 @@
/* FIXME: RC_KEYPRESS_TIMEOUT should be protocol specific */
#define RC_KEYPRESS_TIMEOUT 250
+/**
+ * struct rc_scan - rcu-friendly scancode<->keycode table
+ * @len: number of elements in the table array
+ * @table: array of struct rc_map_table elements
+ */
+struct rc_scan {
+ unsigned len;
+ struct rc_map_table table[];
+};
+
+/**
+ * struct rc_keytable - represents one keytable for a rc_dev device
+ * @node: used to iterate over all keytables for a rc_dev device
+ * @dev: the rc_dev device this keytable belongs to
+ * @idev: the input_dev device which belongs to this keytable
+ * @name: the user-friendly name of this keytable
+ * @scan_mutex: protects @scan against concurrent writers
+ * @scan: the current scancode<->keycode table
+ * @key_lock: protects the key state
+ * @key_pressed: whether a key is currently pressed or not
+ * @last_keycode: keycode of the last keypress
+ * @last_protocol: protocol of the last keypress
+ * @last_scancode: scancode of the last keypress
+ * @last_toggle: toggle of the last keypress
+ * @timer_keyup: responsible for the auto-release of keys
+ * @keyup_jiffies: when the key should be auto-released
+ */
+struct rc_keytable {
+ struct list_head node;
+ struct rc_dev *dev;
+ struct input_dev *idev;
+ char name[RC_KEYTABLE_NAME_SIZE];
+ struct mutex scan_mutex;
+ struct rc_scan __rcu *scan;
+ spinlock_t key_lock;
+ bool key_pressed;
+ u32 last_keycode;
+ enum rc_type last_protocol;
+ u64 last_scancode;
+ u8 last_toggle;
+ struct timer_list timer_keyup;
+ unsigned long keyup_jiffies;
+};
+
/* Used to keep track of known keymaps */
static LIST_HEAD(rc_map_list);
static DEFINE_SPINLOCK(rc_map_lock);
@@ -557,19 +601,26 @@ static void rc_do_keyup(struct rc_keytable *kt, bool sync)
/**
* rc_keyup() - signals the release of a keypress
- * @kt: the struct rc_keytable descriptor of the keytable
+ * @dev: the struct rc_dev descriptor of the device
*
* This routine is used to signal that a key has been released on the
* remote control.
*/
-void rc_keytable_keyup(struct rc_keytable *kt)
+void rc_keyup(struct rc_dev *dev)
{
+ struct rc_keytable *kt;
unsigned long flags;
- spin_lock_irqsave(&kt->key_lock, flags);
- rc_do_keyup(kt, true);
- spin_unlock_irqrestore(&kt->key_lock, flags);
+ rcu_read_lock();
+ list_for_each_entry_rcu(kt, &dev->keytable_list, node) {
+ spin_lock_irqsave(&kt->key_lock, flags);
+ rc_do_keyup(kt, true);
+ spin_unlock_irqrestore(&kt->key_lock, flags);
+ }
+ rcu_read_unlock();
}
+EXPORT_SYMBOL_GPL(rc_keyup);
+
/**
* rc_timer_keyup() - generates a keyup event after a timeout
@@ -601,22 +652,32 @@ static void rc_timer_keyup(unsigned long cookie)
/**
* rc_repeat() - signals that a key is still pressed
- * @kt: the struct rc_keytable descriptor of the keytable
+ * @dev: the struct rc_dev descriptor of the device
*
- * This routine is used when a repeat message which does not include the
- * necessary bits to reproduce the scancode has been received.
+ * This routine is used by when a repeat message which does
+ * not include the necessary bits to reproduce the scancode has been
+ * received.
*/
-void rc_keytable_repeat(struct rc_keytable *kt)
+void rc_repeat(struct rc_dev *dev)
{
+ struct rc_keytable *kt;
unsigned long flags;
- spin_lock_irqsave(&kt->key_lock, flags);
- if (kt->key_pressed) {
- kt->keyup_jiffies = jiffies + msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
- mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
+ rcu_read_lock();
+ list_for_each_entry_rcu(kt, &dev->keytable_list, node) {
+ spin_lock_irqsave(&kt->key_lock, flags);
+ if (kt->key_pressed) {
+ kt->keyup_jiffies = jiffies +
+ msecs_to_jiffies(RC_KEYPRESS_TIMEOUT);
+ mod_timer(&kt->timer_keyup, kt->keyup_jiffies);
+ }
+ spin_unlock_irqrestore(&kt->key_lock, flags);
}
- spin_unlock_irqrestore(&kt->key_lock, flags);
+ rcu_read_unlock();
+
+ rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
}
+EXPORT_SYMBOL_GPL(rc_repeat);
/**
* rc_keytable_keydown() - generates input event for a key press
@@ -629,8 +690,8 @@ void rc_keytable_repeat(struct rc_keytable *kt)
*
* This routine is used to signal that a keypress has been detected.
*/
-void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
- u64 scancode, u8 toggle, bool autoup)
+static void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
+ u64 scancode, u8 toggle, bool autoup)
{
struct rc_scan *scan;
unsigned index;
@@ -677,6 +738,35 @@ void rc_keytable_keydown(struct rc_keytable *kt, enum rc_type protocol,
}
/**
+ * rc_do_keydown() - generates input event for a key press
+ * @dev: the struct rc_dev descriptor of the device
+ * @protocol: the protocol for the keypress
+ * @scancode: the scancode for the keypress
+ * @toggle: the toggle value (protocol dependent, if the protocol doesn't
+ * support toggle values, this should be set to zero)
+ * @autoup: should an automatic keyup event be generated in the future
+ *
+ * This routine is used to signal that a key has been pressed on the
+ * remote control.
+ */
+void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol,
+ u64 scancode, u8 toggle, bool autoup)
+{
+ struct rc_keytable *kt;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(kt, &dev->keytable_list, node)
+ rc_keytable_keydown(kt, protocol, scancode, toggle, autoup);
+ rcu_read_unlock();
+
+ rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
+ rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
+ rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
+}
+EXPORT_SYMBOL_GPL(rc_do_keydown);
+
+
+/**
* rc_input_open() - called on the initial use of the input device
* @idev: the struct input_dev corresponding to the given keytable
* @return: zero on success, otherwise a negative error code
@@ -755,31 +845,67 @@ static int rc_keytable_init(struct rc_keytable *kt,
}
/**
- * rc_keytable_create() - creates a new keytable
+ * rc_keytable_get_name() - get the name of a keytable
+ * @dev:
+ * @dev: the struct rc_dev device the keytable belongs to
+ * @i: the index of the keytable
+ * @buf: the buffer to write the name to
+ * @bufsize: the size of the buffer
+ * @return: zero on success or negative error code
+ *
+ * This function is used to get the userfriendly name of a keytable.
+ */
+int rc_keytable_get_name(struct rc_dev *dev, unsigned i,
+ char *buf, size_t bufsize)
+{
+ struct rc_keytable *kt;
+
+ rcu_read_lock();
+ kt = rcu_dereference(dev->keytables[i]);
+ if (kt) {
+ buf[0] = '\0';
+ strncat(buf, kt->name, bufsize);
+ }
+ rcu_read_unlock();
+
+ return kt ? 0 : -EINVAL;
+}
+
+
+/**
+ * rc_keytable_add() - creates a new keytable
* @dev: the struct rc_dev device this keytable should belong to
* @name: the userfriendly name of this keymap
* @map_name: the name of the keymap to autoload
- * @return: a new struct rc_keytable pointer or NULL on error
+ * @return: the index of the new rc_keytable or a negative error number
*
* This function creates a new keytable (essentially the combination of a
* keytable and an input device along with some state (whether a key
* is currently pressed or not, etc).
*/
-struct rc_keytable *rc_keytable_create(struct rc_dev *dev,
- const char *name,
- const char *map_name)
+int rc_keytable_add(struct rc_dev *dev, const char *name, const char *map_name)
{
struct rc_keytable *kt;
+ unsigned i;
struct input_dev *idev = NULL;
int error;
+ for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
+ if (!dev->keytables[i])
+ break;
+
+ if (i >= ARRAY_SIZE(dev->keytables))
+ return -ENFILE;
+
kt = kzalloc(sizeof(*kt), GFP_KERNEL);
if (!kt)
- return NULL;
+ return -ENOMEM;
idev = input_allocate_device();
- if (!idev)
- goto out;
+ if (!idev) {
+ error = -ENOMEM;
+ goto out_kt;
+ }
kt->idev = idev;
kt->dev = dev;
@@ -795,7 +921,7 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev,
error = rc_keytable_init(kt, rc_map_get(map_name));
if (error)
- goto out;
+ goto out_idev;
idev->dev.parent = &dev->dev;
memcpy(&idev->id, &dev->input_id, sizeof(dev->input_id));
@@ -822,26 +948,49 @@ struct rc_keytable *rc_keytable_create(struct rc_dev *dev,
spin_lock_init(&kt->key_lock);
mutex_init(&kt->scan_mutex);
- return kt;
+
+ rcu_assign_pointer(dev->keytables[i], kt);
+ list_add_rcu(&kt->node, &dev->keytable_list);
+ synchronize_rcu();
+ rc_event(dev, RC_CORE, RC_CORE_KT_ADDED, i);
+
+ return i;
out_table:
kfree(kt->scan);
-out:
+out_idev:
input_free_device(idev);
+out_kt:
kfree(kt);
- return NULL;
+ return error;
}
/**
- * rc_keytable_destroy() - destroys a keytable
- * @dev: the struct rc_keytable to destroy
+ * rc_keytable_remove() - removes a keytable
+ * @dev: the struct rc_dev device the keytable belongs to
+ * @i: the index of the keytable
+ * @return: zero on success or negative error number
*
- * This function destroys an existing keytable.
+ * This function removes an existing keytable.
*/
-void rc_keytable_destroy(struct rc_keytable *kt)
+int rc_keytable_remove(struct rc_dev *dev, unsigned i)
{
+ struct rc_keytable *kt;
+
+ kt = dev->keytables[i];
+ rcu_assign_pointer(dev->keytables[i], NULL);
+ if (kt)
+ list_del_rcu(&kt->node);
+ synchronize_rcu();
+
+ if (!kt)
+ return -EINVAL;
+
+ rc_event(dev, RC_CORE, RC_CORE_KT_REMOVED, i);
del_timer_sync(&kt->timer_keyup);
input_unregister_device(kt->idev);
kfree(kt->scan);
kfree(kt);
+
+ return 0;
}
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index b16dbf4..e2aa7b1 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -101,73 +101,6 @@ void rc_event(struct rc_dev *dev, u16 type, u16 code, u64 val)
}
EXPORT_SYMBOL_GPL(rc_event);
-/**
- * rc_keyup() - signals the release of a keypress
- * @dev: the struct rc_dev descriptor of the device
- *
- * This routine is used to signal that a key has been released on the
- * remote control.
- */
-void rc_keyup(struct rc_dev *dev)
-{
- struct rc_keytable *kt;
-
- rcu_read_lock();
- list_for_each_entry_rcu(kt, &dev->keytable_list, node)
- rc_keytable_keyup(kt);
- rcu_read_unlock();
-}
-EXPORT_SYMBOL_GPL(rc_keyup);
-
-/**
- * rc_repeat() - signals that a key is still pressed
- * @dev: the struct rc_dev descriptor of the device
- *
- * This routine is used by IR decoders when a repeat message which does
- * not include the necessary bits to reproduce the scancode has been
- * received.
- */
-void rc_repeat(struct rc_dev *dev)
-{
- struct rc_keytable *kt;
-
- rcu_read_lock();
- list_for_each_entry_rcu(kt, &dev->keytable_list, node)
- rc_keytable_repeat(kt);
- rcu_read_unlock();
-
- rc_event(dev, RC_KEY, RC_KEY_REPEAT, 1);
-}
-EXPORT_SYMBOL_GPL(rc_repeat);
-
-/**
- * rc_do_keydown() - generates input event for a key press
- * @dev: the struct rc_dev descriptor of the device
- * @protocol: the protocol for the keypress
- * @scancode: the scancode for the keypress
- * @toggle: the toggle value (protocol dependent, if the protocol doesn't
- * support toggle values, this should be set to zero)
- * @autoup: should an automatic keyup event be generated in the future
- *
- * This routine is used to signal that a key has been pressed on the
- * remote control.
- */
-void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol,
- u64 scancode, u8 toggle, bool autoup)
-{
- struct rc_keytable *kt;
-
- rcu_read_lock();
- list_for_each_entry_rcu(kt, &dev->keytable_list, node)
- rc_keytable_keydown(kt, protocol, scancode, toggle, autoup);
- rcu_read_unlock();
-
- rc_event(dev, RC_KEY, RC_KEY_PROTOCOL, protocol);
- rc_event(dev, RC_KEY, RC_KEY_SCANCODE, scancode);
- rc_event(dev, RC_KEY, RC_KEY_TOGGLE, toggle);
-}
-EXPORT_SYMBOL_GPL(rc_do_keydown);
-
/* class for /sys/class/rc */
static char *rc_devnode(struct device *dev, umode_t *mode)
{
@@ -493,48 +426,6 @@ void rc_free_device(struct rc_dev *dev)
}
EXPORT_SYMBOL_GPL(rc_free_device);
-static int rc_add_keytable(struct rc_dev *dev, const char *name,
- const char *map_name)
-{
- struct rc_keytable *kt;
- unsigned i;
-
- for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
- if (!dev->keytables[i])
- break;
-
- if (i >= ARRAY_SIZE(dev->keytables))
- return -ENFILE;
-
- kt = rc_keytable_create(dev, name, map_name);
- if (!kt)
- return -ENOMEM;
-
- rcu_assign_pointer(dev->keytables[i], kt);
- list_add_rcu(&kt->node, &dev->keytable_list);
- synchronize_rcu();
- rc_event(dev, RC_CORE, RC_CORE_KT_ADDED, i);
- return 0;
-}
-
-static int rc_remove_keytable(struct rc_dev *dev, unsigned i)
-{
- struct rc_keytable *kt;
-
- kt = dev->keytables[i];
- rcu_assign_pointer(dev->keytables[i], NULL);
- if (kt)
- list_del_rcu(&kt->node);
- synchronize_rcu();
-
- if (!kt)
- return -EINVAL;
-
- rc_keytable_destroy(kt);
- rc_event(dev, RC_CORE, RC_CORE_KT_REMOVED, i);
- return 0;
-}
-
static u64 rc_get_allowed_protocols(struct rc_dev *dev)
{
return dev ? dev->allowed_protos : 0x0;
@@ -590,7 +481,7 @@ int rc_register_device(struct rc_dev *dev)
if (rc)
goto out_chardev;
- rc = rc_add_keytable(dev, dev->map_name, dev->map_name);
+ rc = rc_keytable_add(dev, dev->map_name, dev->map_name);
if (rc < 0)
goto out_device;
@@ -628,7 +519,7 @@ void rc_unregister_device(struct rc_dev *dev)
mutex_lock(&dev->mutex);
dev->exist = false;
for (i = 0; i < ARRAY_SIZE(dev->keytables); i++)
- rc_remove_keytable(dev, i);
+ rc_keytable_remove(dev, i);
mutex_unlock(&dev->mutex);
mutex_lock(&rc_dev_table_mutex);
@@ -923,7 +814,6 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
struct rc_ir_rx rx;
struct rc_ir_tx tx;
struct rc_keytable_ioctl ktio;
- struct rc_keytable *kt;
int error;
switch (cmd) {
@@ -1000,7 +890,7 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
if (strlen(ktio.name) < 1)
return -EINVAL;
- error = rc_add_keytable(dev, ktio.name, NULL);
+ error = rc_keytable_add(dev, ktio.name, NULL);
if (error < 0)
return error;
ktio.id = error;
@@ -1020,16 +910,10 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
if (ktio.flags)
return -EINVAL;
- rcu_read_lock();
- kt = rcu_dereference(dev->keytables[ktio.id]);
- if (kt) {
- ktio.name[0] = '\0';
- strncat(ktio.name, kt->name, sizeof(ktio.name));
- }
- rcu_read_unlock();
-
- if (!kt)
- return -EINVAL;
+ error = rc_keytable_get_name(dev, ktio.id,
+ ktio.name, sizeof(ktio.name));
+ if (error)
+ return error;
if (copy_to_user(p, &ktio, sizeof(ktio)))
return -EFAULT;
@@ -1046,7 +930,7 @@ static long rc_do_ioctl(struct rc_dev *dev, unsigned int cmd, unsigned long arg)
if (ktio.flags)
return -EINVAL;
- return rc_remove_keytable(dev, ktio.id);
+ return rc_keytable_remove(dev, ktio.id);
}
return -EINVAL;
}
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 056275a..e311242 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -351,50 +351,6 @@ struct rc_dev {
int (*set_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
};
-/**
- * struct rc_scan - rcu-friendly scancode<->keycode table
- * @len: number of elements in the table array
- * @table: array of struct rc_map_table elements
- */
-struct rc_scan {
- unsigned len;
- struct rc_map_table table[];
-};
-
-/**
- * struct rc_keytable - represents one keytable for a rc_dev device
- * @node: used to iterate over all keytables for a rc_dev device
- * @dev: the rc_dev device this keytable belongs to
- * @idev: the input_dev device which belongs to this keytable
- * @name: the user-friendly name of this keytable
- * @scan_mutex: protects @scan against concurrent writers
- * @scan: the current scancode<->keycode table
- * @key_lock: protects the key state
- * @key_pressed: whether a key is currently pressed or not
- * @last_keycode: keycode of the last keypress
- * @last_protocol: protocol of the last keypress
- * @last_scancode: scancode of the last keypress
- * @last_toggle: toggle of the last keypress
- * @timer_keyup: responsible for the auto-release of keys
- * @keyup_jiffies: when the key should be auto-released
- */
-struct rc_keytable {
- struct list_head node;
- struct rc_dev *dev;
- struct input_dev *idev;
- char name[RC_KEYTABLE_NAME_SIZE];
- struct mutex scan_mutex;
- struct rc_scan __rcu *scan;
- spinlock_t key_lock;
- bool key_pressed;
- u32 last_keycode;
- enum rc_type last_protocol;
- u64 last_scancode;
- u8 last_toggle;
- struct timer_list timer_keyup;
- unsigned long keyup_jiffies;
-};
-
#define to_rc_dev(d) container_of(d, struct rc_dev, dev)
/*
^ permalink raw reply related [flat|nested] 45+ messages in thread* [PATCH 43/43] rc-core: make rc-core.h userspace friendly
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (41 preceding siblings ...)
2012-05-23 9:45 ` [PATCH 42/43] rc-core: move remaining keytable functions David Härdeman
@ 2012-05-23 9:45 ` David Härdeman
2012-06-22 17:37 ` [PATCH 00/43] rc-core: feature parity with LIRC Mauro Carvalho Chehab
43 siblings, 0 replies; 45+ messages in thread
From: David Härdeman @ 2012-05-23 9:45 UTC (permalink / raw)
To: linux-media; +Cc: mchehab, jarod
A few ifdef __KERNEL__ and some reorganisation to make rc-core.h usable from
userspace programs.
Signed-off-by: David Härdeman <david@hardeman.nu>
---
include/media/rc-core.h | 76 +++++++++++++++++++++++++++++++++--------------
1 file changed, 54 insertions(+), 22 deletions(-)
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index e311242..0685a4c 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -16,20 +16,21 @@
#ifndef _RC_CORE
#define _RC_CORE
+#ifdef __KERNEL__
#include <linux/spinlock.h>
#include <linux/kfifo.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <media/rc-map.h>
+#else
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <linux/types.h>
+#endif
-extern int rc_core_debug;
-#define IR_dprintk(level, fmt, ...) \
-do { \
- if (rc_core_debug >= level) \
- pr_debug("%s: " fmt, __func__, ##__VA_ARGS__); \
-} while (0)
-
-#define RC_VERSION 0x010000
+#define RC_VERSION 0x010000
+#define RC_MAX_KEYTABLES 32
/*
* ioctl definitions
@@ -176,18 +177,37 @@ struct rc_keytable_ioctl {
char name[RC_KEYTABLE_NAME_SIZE];
} __packed;
+/**
+ * enum rc_driver_type - describe the kind of driver/hardware used
+ * @RC_DRIVER_SCANCODE: generates scancodes
+ * @RC_DRIVER_IR_RAW: generates IR timings which need to be decoded
+ */
enum rc_driver_type {
- RC_DRIVER_SCANCODE = 0, /* Driver or hardware generates a scancode */
- RC_DRIVER_IR_RAW, /* Needs a Infra-Red pulse/space decoder */
+ RC_DRIVER_SCANCODE = 0,
+ RC_DRIVER_IR_RAW,
};
-/* This is used for the input EVIOC[SG]KEYCODE_V2 ioctls */
+/**
+ * struct rc_scancode - protocol/scancode pair
+ * @protocol: the protocol of the rc command
+ * @reserved: for future use and padding, set to zero
+ * @scancode: the scancode of the command
+ */
struct rc_scancode {
__u16 protocol;
__u16 reserved[3];
__u64 scancode;
};
+/**
+ * struct rc_keymap_entry - used in EVIOC[SG]KEYCODE_V2 ioctls
+ * @flags: see &struct input_keymap_entry
+ * @len: see &struct input_keymap_entry
+ * @index: see &struct input_keymap_entry
+ * @keycode: see &struct input_keymap_entry
+ * @rc: the scancode/protocol definition, see &struct rc_scancode
+ * @raw: alternative representation of @rc
+ */
struct rc_keymap_entry {
__u8 flags;
__u8 len;
@@ -203,7 +223,7 @@ struct rc_keymap_entry {
* struct rc_event - used to communicate rc events to userspace
* @type: the event type
* @code: the event code (type specific)
- * @reserved: zero for now
+ * @reserved: padding, zero for now
* @val: the event value (type and code specific)
*/
struct rc_event {
@@ -239,6 +259,9 @@ struct rc_event {
#define RC_IR_RAW_CARRIER 0x5
#define RC_IR_RAW_DUTY_CYCLE 0x6
+#ifdef __KERNEL__
+/* The rest is implementational details which shouldn't concern userspace */
+
/**
* struct rc_dev - represents a remote control device
* @dev: driver model's view of this device
@@ -300,7 +323,6 @@ struct rc_event {
* @get_ir_tx: allow driver to provide tx settings
* @set_ir_tx: allow driver to change tx settings
*/
-#define RC_MAX_KEYTABLES 32
#define RC_TX_KFIFO_SIZE 1024
struct rc_dev {
struct device dev;
@@ -350,22 +372,16 @@ struct rc_dev {
void (*get_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
int (*set_ir_tx)(struct rc_dev *dev, struct rc_ir_tx *tx);
};
-
#define to_rc_dev(d) container_of(d, struct rc_dev, dev)
-/*
- * From rc-main.c
- * Those functions can be used on any type of Remote Controller. They
- * basically creates an input_dev and properly reports the device as a
- * Remote Controller, at sys/class/rc.
- */
-
+/* From rc-main.c - see inline kerneldoc */
struct rc_dev *rc_allocate_device(void);
void rc_free_device(struct rc_dev *dev);
int rc_register_device(struct rc_dev *dev);
void rc_unregister_device(struct rc_dev *dev);
void rc_event(struct rc_dev *dev, u16 type, u16 code, u64 val);
+/* From rc-keytable.c - see inline kerneldoc */
void rc_repeat(struct rc_dev *dev);
void rc_keyup(struct rc_dev *dev);
void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol, u64 scancode, u8 toggle, bool autoup);
@@ -373,7 +389,22 @@ void rc_do_keydown(struct rc_dev *dev, enum rc_type protocol, u64 scancode, u8 t
#define rc_keydown_notimeout(dev, proto, scan, toggle) rc_do_keydown(dev, proto, scan, toggle, false)
u32 rc_g_keycode_from_table(struct rc_dev *dev, enum rc_type protocol, u64 scancode);
-/* extract mask bits out of data and pack them into the result */
+extern int rc_core_debug;
+#define IR_dprintk(level, fmt, ...) \
+do { \
+ if (rc_core_debug >= level) \
+ pr_debug("%s: " fmt, __func__, ##__VA_ARGS__); \
+} while (0)
+
+/**
+ * ir_extract_bits() - extract bits of data according to a mask
+ * @data: the data to extract bits from
+ * @mask: the mask of bits to extract
+ * @return: the extracted bits packed together
+ *
+ * This helper function is used by some drivers to extract the relevant
+ * (masked) bits of data.
+ */
static inline u32 ir_extract_bits(u32 data, u32 mask)
{
u32 vbit = 1, value = 0;
@@ -390,4 +421,5 @@ static inline u32 ir_extract_bits(u32 data, u32 mask)
return value;
}
+#endif /* __KERNEL__ */
#endif /* _RC_CORE */
^ permalink raw reply related [flat|nested] 45+ messages in thread* Re: [PATCH 00/43] rc-core: feature parity with LIRC
2012-05-23 9:42 [PATCH 00/43] rc-core: feature parity with LIRC David Härdeman
` (42 preceding siblings ...)
2012-05-23 9:45 ` [PATCH 43/43] rc-core: make rc-core.h userspace friendly David Härdeman
@ 2012-06-22 17:37 ` Mauro Carvalho Chehab
43 siblings, 0 replies; 45+ messages in thread
From: Mauro Carvalho Chehab @ 2012-06-22 17:37 UTC (permalink / raw)
To: David Härdeman; +Cc: linux-media, jarod
Hi David,
Em 23-05-2012 06:42, David Härdeman escreveu:
> The following patchset provides most of the features necessary for parity with
> the LIRC subsystem that rc-core is intended to replace.
>
> Most importantly, a chardev is provided which can be used to control RC hardware
> using read (RX), write (TX) and ioctl (setting RX/TX parameters).
>
> The patchset still needs further testing and I am well aware that patches will
> be necessary to the current userspace tools as well. However, I'd like to get
> the discussion started on whether the API needs any changes before I invest more
> time in testing and patches to other tools.
>
> Code review is welcome but the most important part is the userspace<->kernel
> interface (i.e. the read/write/ioctl interface).
Didn't have time yet to dig into this big patch series. Also, I'm expecting Jarod's
review on it, as he's the maintainer of the lirc drivers.
Yet, one thing that this patch series is doing is that it is changing the current
interface, and will likely break the existing userspace applications. This is not
allowed. Deprecating existing interfaces in favor of newer ones is possible, but
this will require to mark the affected sysfs nodes to be marked as deprecated at
Documentation/feature-removal-schedule.txt, and a new set of them to be added with
the new interface.
Before that, however, we need to be convinced why such change is required.
Also, analyzing a 43 patch series require reviewers/maintainers to reserve a big
window just for this series. It is a way better if you break it into smaller
patch series.
Based solely on the patch names, it seems that there are several different things there:
- RC API changes;
- LIRC API additions;
- Some "independent" patches (kmaloc removal, debug cleanup, etc);
- rc-core improvements.
I suggest you to split the patch series, starting with the more obvious changes.
Then, we can go into RC API changes and lirc API additions.
Regards,
Mauro
>
> Comments?
>
> ---
>
> David Härdeman (43):
> rc-core: move timeout and checks to lirc
> rc-core: add separate defines for protocol bitmaps and numbers
> rc-core: don't throw away protocol information
> rc-core: use the full 32 bits for NEC scancodes
> rc-core: merge rc5 and streamzap decoders
> rc-core: rename ir_input_class to rc_class
> rc-core: initialize rc-core earlier if built-in
> rc-core: use a device table rather than an atomic number
> rc-core: add chardev
> rc-core: allow chardev to be read
> mceusb: remove pointless kmalloc
> redrat: cleanup debug functions
> rc-core: use a kfifo for TX data
> rc-core: allow chardev to be written
> rc-core: add ioctl support to the rc chardev
> rc-core: add an ioctl for getting IR RX settings
> rc-loopback: add RCIOCGIRRX ioctl support
> rc-core: add an ioctl for setting IR RX settings
> rc-loopback: add RCIOCSIRRX ioctl support
> rc-core: add an ioctl for getting IR TX settings
> rc-loopback: add RCIOCGIRTX ioctl support
> rc-core: add an ioctl for setting IR TX settings
> rc-loopback: add RCIOCSIRTX ioctl support
> rc-core: leave the internals of rc_dev alone
> rc-core: prepare for multiple keytables
> rc-core: do not take mutex on rc_dev registration
> rc-core: make the keytable of rc_dev an array
> rc-core: add ioctls for adding/removing keytables from userspace
> rc-core: remove redundant spinlock
> rc-core: make keytable RCU-friendly
> rc-core: allow empty keymaps
> rc-core: split IR raw handling to a separate module
> rc-ir-raw: simplify locking
> rc-core: rename mutex
> rc-ir-raw: atomic reads of protocols
> rc-core: fix various sparse warnings
> rc-core: don't report scancodes via input devices
> rc-ir-raw: add various rc_events
> rc-core: use struct rc_event to signal TX events from userspace
> rc-core: use struct rc_event for all rc communication
> rc-core: add keytable events
> rc-core: move remaining keytable functions
> rc-core: make rc-core.h userspace friendly
>
>
> Documentation/ioctl/ioctl-number.txt | 1
> drivers/media/dvb/dm1105/dm1105.c | 3
> drivers/media/dvb/dvb-usb/Kconfig | 2
> drivers/media/dvb/dvb-usb/af9015.c | 38 -
> drivers/media/dvb/dvb-usb/af9035.c | 25
> drivers/media/dvb/dvb-usb/anysee.c | 4
> drivers/media/dvb/dvb-usb/az6007.c | 19
> drivers/media/dvb/dvb-usb/dib0700_core.c | 11
> drivers/media/dvb/dvb-usb/dib0700_devices.c | 156 +-
> drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 11
> drivers/media/dvb/dvb-usb/dvb-usb.h | 4
> drivers/media/dvb/dvb-usb/it913x.c | 24
> drivers/media/dvb/dvb-usb/lmedm04.c | 11
> drivers/media/dvb/dvb-usb/pctv452e.c | 15
> drivers/media/dvb/dvb-usb/rtl28xxu.c | 32
> drivers/media/dvb/dvb-usb/technisat-usb2.c | 17
> drivers/media/dvb/dvb-usb/ttusb2.c | 4
> drivers/media/dvb/mantis/mantis_input.c | 2
> drivers/media/dvb/siano/Kconfig | 2
> drivers/media/dvb/siano/smsir.c | 13
> drivers/media/dvb/siano/smsir.h | 2
> drivers/media/dvb/ttpci/budget-ci.c | 7
> drivers/media/rc/Kconfig | 66 +
> drivers/media/rc/Makefile | 4
> drivers/media/rc/ati_remote.c | 18
> drivers/media/rc/ene_ir.c | 69 -
> drivers/media/rc/ene_ir.h | 9
> drivers/media/rc/fintek-cir.c | 30
> drivers/media/rc/gpio-ir-recv.c | 11
> drivers/media/rc/imon.c | 45 -
> drivers/media/rc/ir-jvc-decoder.c | 54 -
> drivers/media/rc/ir-lirc-codec.c | 191 ++-
> drivers/media/rc/ir-mce_kbd-decoder.c | 38 -
> drivers/media/rc/ir-nec-decoder.c | 93 +
> drivers/media/rc/ir-raw.c | 374 ------
> drivers/media/rc/ir-rc5-decoder.c | 94 +
> drivers/media/rc/ir-rc5-sz-decoder.c | 154 --
> drivers/media/rc/ir-rc6-decoder.c | 102 +-
> drivers/media/rc/ir-sanyo-decoder.c | 62 -
> drivers/media/rc/ir-sony-decoder.c | 59 +
> drivers/media/rc/ite-cir.c | 57 -
> drivers/media/rc/ite-cir.h | 2
> drivers/media/rc/keymaps/rc-imon-mce.c | 2
> drivers/media/rc/keymaps/rc-rc6-mce.c | 2
> drivers/media/rc/keymaps/rc-streamzap.c | 4
> drivers/media/rc/mceusb.c | 125 +-
> drivers/media/rc/nuvoton-cir.c | 83 +
> drivers/media/rc/nuvoton-cir.h | 9
> drivers/media/rc/rc-core-priv.h | 62 +
> drivers/media/rc/rc-ir-raw.c | 375 ++++++
> drivers/media/rc/rc-keytable.c | 996 +++++++++++++++
> drivers/media/rc/rc-loopback.c | 212 ++-
> drivers/media/rc/rc-main.c | 1575 +++++++++++-------------
> drivers/media/rc/redrat3.c | 336 ++---
> drivers/media/rc/streamzap.c | 80 +
> drivers/media/rc/winbond-cir.c | 61 -
> drivers/media/video/bt8xx/bttv-input.c | 15
> drivers/media/video/cx18/cx18-i2c.c | 2
> drivers/media/video/cx231xx/cx231xx-input.c | 9
> drivers/media/video/cx23885/Kconfig | 2
> drivers/media/video/cx23885/cx23885-input.c | 21
> drivers/media/video/cx23885/cx23888-ir.c | 93 +
> drivers/media/video/cx25840/cx25840-ir.c | 96 +
> drivers/media/video/cx88/Kconfig | 2
> drivers/media/video/cx88/cx88-input.c | 43 -
> drivers/media/video/em28xx/em28xx-cards.c | 15
> drivers/media/video/em28xx/em28xx-input.c | 38 -
> drivers/media/video/em28xx/em28xx.h | 1
> drivers/media/video/hdpvr/hdpvr-i2c.c | 2
> drivers/media/video/ir-kbd-i2c.c | 30
> drivers/media/video/ivtv/ivtv-i2c.c | 10
> drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 4
> drivers/media/video/saa7134/Kconfig | 2
> drivers/media/video/saa7134/saa7134-input.c | 12
> drivers/media/video/saa7134/saa7134.h | 2
> drivers/media/video/tm6000/tm6000-cards.c | 2
> drivers/media/video/tm6000/tm6000-input.c | 79 +
> include/media/ir-kbd-i2c.h | 2
> include/media/rc-core.h | 404 +++++-
> include/media/rc-ir-raw.h | 78 +
> include/media/rc-map.h | 88 +
> 81 files changed, 3949 insertions(+), 2960 deletions(-)
> delete mode 100644 drivers/media/rc/ir-raw.c
> delete mode 100644 drivers/media/rc/ir-rc5-sz-decoder.c
> create mode 100644 drivers/media/rc/rc-ir-raw.c
> create mode 100644 drivers/media/rc/rc-keytable.c
> create mode 100644 include/media/rc-ir-raw.h
>
^ permalink raw reply [flat|nested] 45+ messages in thread