* [RFCv2 PATCH 1/5] rc-core: Add defintions needed for sysfs callback
2014-01-26 21:50 [RFCv2 PATCH 0/5] rc: Add generic sysfs interface for handling wakeup codes Antti Seppälä
@ 2014-01-26 21:50 ` Antti Seppälä
2014-01-26 21:50 ` [RFCv2 PATCH 2/5] rc-core: Add support for reading/writing wakeup codes via sysfs Antti Seppälä
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Antti Seppälä @ 2014-01-26 21:50 UTC (permalink / raw)
To: linux-media; +Cc: Mauro Carvalho Chehab, Sean Young, Antti Seppälä
Introduce a list for wake code values and add callback for reading
/ writing it via sysfs.
Also introduce bitfields for setting which protocols are allowed and
enabled for wakeup.
Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
---
include/media/rc-core.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 2f6f1f7..e0e5699 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -20,6 +20,7 @@
#include <linux/kfifo.h>
#include <linux/time.h>
#include <linux/timer.h>
+#include <linux/list.h>
#include <media/rc-map.h>
extern int rc_core_debug;
@@ -35,6 +36,16 @@ enum rc_driver_type {
};
/**
+ * struct rc_wakeup_code - represents a single IR scancode or pulse/space
+ * @value: scan code value or pulse (+) / space (-) length
+ * @list: linked list pointer
+ */
+struct rc_wakeup_code {
+ s32 value;
+ struct list_head list_item;
+};
+
+/**
* struct rc_dev - represents a remote control device
* @dev: driver model's view of this device
* @input_name: name of the input child device
@@ -52,6 +63,8 @@ enum rc_driver_type {
* @idle: used to keep track of RX state
* @allowed_protos: bitmask with the supported RC_BIT_* protocols
* @enabled_protocols: bitmask with the enabled RC_BIT_* protocols
+ * @allowed_wake_protos: bitmask with the supported RC_BIT_* protocols for wakeup
+ * @enabled_wake_protos: bitmask with the enabled RC_BIT_* protocols for wakeup
* @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
@@ -84,6 +97,7 @@ enum rc_driver_type {
* 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_wakeup_codes: set/get IR scancode to wake hardware from sleep states
*/
struct rc_dev {
struct device dev;
@@ -101,6 +115,8 @@ struct rc_dev {
bool idle;
u64 allowed_protos;
u64 enabled_protocols;
+ u64 allowed_wake_protos;
+ u64 enabled_wake_protos;
u32 users;
u32 scanmask;
void *priv;
@@ -127,6 +143,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);
+ int (*s_wakeup_codes) (struct rc_dev *dev, struct list_head *wakeup_code_list, int write);
};
#define to_rc_dev(d) container_of(d, struct rc_dev, dev)
--
1.8.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread* [RFCv2 PATCH 2/5] rc-core: Add support for reading/writing wakeup codes via sysfs
2014-01-26 21:50 [RFCv2 PATCH 0/5] rc: Add generic sysfs interface for handling wakeup codes Antti Seppälä
2014-01-26 21:50 ` [RFCv2 PATCH 1/5] rc-core: Add defintions needed for sysfs callback Antti Seppälä
@ 2014-01-26 21:50 ` Antti Seppälä
2014-01-26 21:50 ` [RFCv2 PATCH 3/5] rc-loopback: Add support for reading/writing wakeup scancodes " Antti Seppälä
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Antti Seppälä @ 2014-01-26 21:50 UTC (permalink / raw)
To: linux-media; +Cc: Mauro Carvalho Chehab, Sean Young, Antti Seppälä
This patch adds support for two files in sysfs controlling the wakeup
(scan)codes that are written to hardware.
* /sys/class/rc/rc?/wakeup_protocols:
This file has the same syntax as rc protocols file
(/sys/class/rc/rc?/protocols). When read it displays the wakeup
protocols the underlying IR driver supports. Protocol can be changed by
writing it to the file. The active protocol defines how actual
wakeup_code is to be interpreted.
Note: Only one protocol can be active at a time.
* /sys/class/rc/rc?/wakeup_codes:
This file contains the currently active wakeup (scan)code(s).
New values can be written to activate a new wakeup code.
The contents of the wakeup_code file are simply white space separated
values.
Note: Protocol "other" has a special meaning: if activated then
wakeup_codes file will contain raw IR samples. Positive values
represent pulses and negative values spaces.
How to read:
cat /sys/class/rc/rc?/wakeup_codes
How to write:
echo "rc-6" > /sys/class/rc/rc?/wakeup_protocols
echo "0xd1ab" > /sys/class/rc/rc?/wakeup_codes
Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
---
drivers/media/rc/rc-main.c | 179 +++++++++++++++++++++++++++++++++++++++++----
1 file changed, 165 insertions(+), 14 deletions(-)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 02e2f38..cde17e2 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -797,7 +797,7 @@ static struct {
/**
* show_protocols() - shows the current IR protocol(s)
* @device: the device descriptor
- * @mattr: the device attribute struct (unused)
+ * @mattr: the device attribute struct
* @buf: a pointer to the output buffer
*
* This routine is a callback routine for input read the IR protocol type(s).
@@ -822,14 +822,19 @@ 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 if (dev->raw)
- allowed = ir_raw_get_allowed_protocols();
- else {
- mutex_unlock(&dev->lock);
- return -ENODEV;
+ if (strcmp(mattr->attr.name, "wakeup_protocols") == 0) {
+ enabled = dev->enabled_wake_protos;
+ allowed = dev->allowed_wake_protos;
+ } else {
+ enabled = dev->enabled_protocols;
+ if (dev->driver_type == RC_DRIVER_SCANCODE)
+ allowed = dev->allowed_protos;
+ else if (dev->raw)
+ allowed = ir_raw_get_allowed_protocols();
+ else {
+ mutex_unlock(&dev->lock);
+ return -ENODEV;
+ }
}
IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
@@ -858,7 +863,7 @@ static ssize_t show_protocols(struct device *device,
/**
* store_protocols() - changes the current IR protocol(s)
* @device: the device descriptor
- * @mattr: the device attribute struct (unused)
+ * @mattr: the device attribute struct
* @buf: a pointer to the input buffer
* @len: length of the input buffer
*
@@ -884,7 +889,7 @@ static ssize_t store_protocols(struct device *device,
const char *tmp;
u64 type;
u64 mask;
- int rc, i, count = 0;
+ int rc, i, wake = 0, count = 0, enablecount = 0;
ssize_t ret;
/* Device is being removed */
@@ -898,7 +903,13 @@ static ssize_t store_protocols(struct device *device,
ret = -EINVAL;
goto out;
}
- type = dev->enabled_protocols;
+
+ if (strcmp(mattr->attr.name, "wakeup_protocols") == 0) {
+ wake = 1;
+ type = dev->enabled_wake_protos;
+ } else {
+ type = dev->enabled_protocols;
+ }
while ((tmp = strsep((char **) &data, " \n")) != NULL) {
if (!*tmp)
@@ -920,6 +931,8 @@ static ssize_t store_protocols(struct device *device,
for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
if (!strcasecmp(tmp, proto_names[i].name)) {
mask = proto_names[i].type;
+ if (wake && (enable || (!enable && !disable)))
+ enablecount++;
break;
}
}
@@ -946,7 +959,7 @@ static ssize_t store_protocols(struct device *device,
goto out;
}
- if (dev->change_protocol) {
+ if (dev->change_protocol && !wake) {
rc = dev->change_protocol(dev, &type);
if (rc < 0) {
IR_dprintk(1, "Error setting protocols to 0x%llx\n",
@@ -956,7 +969,16 @@ static ssize_t store_protocols(struct device *device,
}
}
- dev->enabled_protocols = type;
+ if (wake && enablecount > 1) {
+ IR_dprintk(1, "Only one wake protocol can be enabled "
+ "at a time\n");
+ ret = -EINVAL;
+ goto out;
+ } else if (wake) {
+ dev->enabled_wake_protos = type;
+ } else {
+ dev->enabled_protocols = type;
+ }
IR_dprintk(1, "Current protocol(s): 0x%llx\n",
(long long)type);
@@ -967,6 +989,121 @@ out:
return ret;
}
+/**
+ * show_wakeup_codes() - shows the current IR wake code(s)
+ * @device: the device descriptor
+ * @mattr: the device attribute struct (unused)
+ * @buf: a pointer to the output buffer
+ *
+ * This routine is a callback routine for input read the IR wake code(s).
+ * it is trigged by reading /sys/class/rc/rc?/wakeup_codes.
+ * It returns the currently active IR wake code or empty buffer if wake
+ * code is not active.
+ *
+ * dev->lock is taken to guard against races between device
+ * registration, store_wakeup_codes and show_wakeup_codes.
+ */
+static ssize_t show_wakeup_codes(struct device *device,
+ struct device_attribute *mattr, char *buf)
+{
+ int ret, pos = 0;
+ struct rc_wakeup_code *code, *next;
+ LIST_HEAD(wakeup_code_list);
+ struct rc_dev *dev = to_rc_dev(device);
+
+ if (!dev || !dev->s_wakeup_codes)
+ return -ENODEV;
+
+ mutex_lock(&dev->lock);
+
+ ret = dev->s_wakeup_codes(dev, &wakeup_code_list, 0);
+
+ list_for_each_entry_safe(code, next, &wakeup_code_list, list_item) {
+ if (dev->enabled_wake_protos & RC_BIT_OTHER)
+ pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ",
+ code->value);
+ else
+ pos += scnprintf(buf + pos, PAGE_SIZE - pos, "0x%x ",
+ code->value);
+ list_del(&code->list_item);
+ kfree(code);
+ }
+ pos += scnprintf(buf + pos, PAGE_SIZE - pos, "\n");
+
+ mutex_unlock(&dev->lock);
+
+ if (ret < 0)
+ return ret;
+
+ return pos;
+}
+
+/**
+ * store_wakeup_codes() - changes the current IR wake code(s)
+ * @device: the device descriptor
+ * @mattr: the device attribute struct (unused)
+ * @buf: a pointer to the input buffer
+ * @len: length of the input buffer
+ *
+ * This routine is for changing the IR wake code.
+ * It is trigged by writing to /sys/class/rc/rc?/wakeup_codes.
+ * Writing bytes separated by white space will pass them to the hardware.
+ * Writing "" (empty) will clear active wake code.
+ * Returns -EINVAL if too many values or invalid values were used
+ * otherwise @len.
+ *
+ * dev->lock is taken to guard against races between device
+ * registration, store_wakeup_codes and show_wakeup_codes.
+ */
+static ssize_t store_wakeup_codes(struct device *device,
+ struct device_attribute *mattr,
+ const char *data,
+ size_t len)
+{
+ int ret = 0;
+ char *tmp;
+ long value;
+ struct rc_wakeup_code *code, *next;
+ LIST_HEAD(wakeup_code_list);
+ struct rc_dev *dev = to_rc_dev(device);
+
+ if (!dev || !dev->s_wakeup_codes)
+ return -ENODEV;
+
+ mutex_lock(&dev->lock);
+
+ while ((tmp = strsep((char **) &data, " ,\t\n")) != NULL) {
+ if (!*tmp)
+ break;
+
+ ret = kstrtol(tmp, 0, &value);
+ if (ret < 0) {
+ IR_dprintk(1, "Error parsing value of %s", tmp);
+ break;
+ }
+
+ code = kmalloc(sizeof(struct rc_wakeup_code), GFP_KERNEL);
+ if (!code) {
+ ret = -ENOMEM;
+ break;
+ }
+ code->value = value;
+ list_add_tail(&code->list_item, &wakeup_code_list);
+ }
+
+ if (!ret)
+ ret = dev->s_wakeup_codes(dev, &wakeup_code_list, 1);
+
+ list_for_each_entry_safe(code, next, &wakeup_code_list, list_item) {
+ list_del(&code->list_item);
+ kfree(code);
+ }
+
+ mutex_unlock(&dev->lock);
+
+ return ret ? ret : len;
+}
+
static void rc_dev_release(struct device *device)
{
}
@@ -998,6 +1135,10 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
*/
static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR,
show_protocols, store_protocols);
+static DEVICE_ATTR(wakeup_protocols, S_IRUGO | S_IWUSR,
+ show_protocols, store_protocols);
+static DEVICE_ATTR(wakeup_codes, S_IRUGO | S_IWUSR,
+ show_wakeup_codes, store_wakeup_codes);
static struct attribute *rc_dev_attrs[] = {
&dev_attr_protocols.attr,
@@ -1175,6 +1316,16 @@ int rc_register_device(struct rc_dev *dev)
dev->enabled_protocols = rc_type;
}
+ /* Create sysfs entry only if device has wake code support */
+ if (dev->s_wakeup_codes) {
+ rc = device_create_file(&dev->dev, &dev_attr_wakeup_codes);
+ if (rc < 0)
+ goto out_raw;
+ rc = device_create_file(&dev->dev, &dev_attr_wakeup_protocols);
+ if (rc < 0)
+ goto out_raw;
+ }
+
mutex_unlock(&dev->lock);
IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n",
--
1.8.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread* [RFCv2 PATCH 3/5] rc-loopback: Add support for reading/writing wakeup scancodes via sysfs
2014-01-26 21:50 [RFCv2 PATCH 0/5] rc: Add generic sysfs interface for handling wakeup codes Antti Seppälä
2014-01-26 21:50 ` [RFCv2 PATCH 1/5] rc-core: Add defintions needed for sysfs callback Antti Seppälä
2014-01-26 21:50 ` [RFCv2 PATCH 2/5] rc-core: Add support for reading/writing wakeup codes via sysfs Antti Seppälä
@ 2014-01-26 21:50 ` Antti Seppälä
2014-01-26 21:50 ` [RFCv2 PATCH 4/5] nuvoton-cir: Add support for reading/writing wakeup samples " Antti Seppälä
2014-01-26 21:50 ` [RFCv2 PATCH 5/5] winbond-cir: Add support for reading/writing wakeup scancodes " Antti Seppälä
4 siblings, 0 replies; 8+ messages in thread
From: Antti Seppälä @ 2014-01-26 21:50 UTC (permalink / raw)
To: linux-media; +Cc: Mauro Carvalho Chehab, Sean Young, Antti Seppälä
This patch adds sample support for reading/writing the wakeup scancodes
to rc-loopback device driver.
Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
---
drivers/media/rc/rc-loopback.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 53d0282..46e76ad 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -26,6 +26,7 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/sched.h>
+#include <linux/slab.h>
#include <media/rc-core.h>
#define DRIVER_NAME "rc-loopback"
@@ -45,6 +46,7 @@ struct loopback_dev {
bool carrierreport;
u32 rxcarriermin;
u32 rxcarriermax;
+ u32 wakeup_scancode;
};
static struct loopback_dev loopdev;
@@ -176,6 +178,41 @@ static int loop_set_carrier_report(struct rc_dev *dev, int enable)
return 0;
}
+static int loop_wakeup_codes(struct rc_dev *dev,
+ struct list_head *wakeup_code_list, int write)
+{
+ u32 value = 0;
+ struct rc_wakeup_code *code;
+ struct loopback_dev *lodev = dev->priv;
+
+ dprintk("%sing wakeup codes\n", write ? "writ" : "read");
+
+ if (write) {
+ code = list_first_entry_or_null(wakeup_code_list,
+ struct rc_wakeup_code,
+ list_item);
+ if (code)
+ value = code->value;
+
+ if (dev->enabled_wake_protos & RC_BIT_RC5) {
+ if (value > 0xFFF)
+ return -EINVAL;
+ } else if (dev->enabled_wake_protos & RC_BIT_RC6_0) {
+ if (value > 0xFFFF)
+ return -EINVAL;
+ }
+
+ lodev->wakeup_scancode = value;
+ } else {
+ code = kmalloc(sizeof(struct rc_wakeup_code), GFP_KERNEL);
+ if (!code)
+ return -ENOMEM;
+ code->value = lodev->wakeup_scancode;
+ list_add_tail(&code->list_item, wakeup_code_list);
+ }
+ return 0;
+}
+
static int __init loop_init(void)
{
struct rc_dev *rc;
@@ -196,6 +233,8 @@ static int __init loop_init(void)
rc->priv = &loopdev;
rc->driver_type = RC_DRIVER_IR_RAW;
rc->allowed_protos = RC_BIT_ALL;
+ rc->allowed_wake_protos = RC_BIT_RC6_0 | RC_BIT_RC5;
+ rc->enabled_wake_protos = RC_BIT_RC6_0;
rc->timeout = 100 * 1000 * 1000; /* 100 ms */
rc->min_timeout = 1;
rc->max_timeout = UINT_MAX;
@@ -209,6 +248,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->s_wakeup_codes = loop_wakeup_codes;
loopdev.txmask = RXMASK_REGULAR;
loopdev.txcarrier = 36000;
--
1.8.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread* [RFCv2 PATCH 4/5] nuvoton-cir: Add support for reading/writing wakeup samples via sysfs
2014-01-26 21:50 [RFCv2 PATCH 0/5] rc: Add generic sysfs interface for handling wakeup codes Antti Seppälä
` (2 preceding siblings ...)
2014-01-26 21:50 ` [RFCv2 PATCH 3/5] rc-loopback: Add support for reading/writing wakeup scancodes " Antti Seppälä
@ 2014-01-26 21:50 ` Antti Seppälä
2014-01-26 21:50 ` [RFCv2 PATCH 5/5] winbond-cir: Add support for reading/writing wakeup scancodes " Antti Seppälä
4 siblings, 0 replies; 8+ messages in thread
From: Antti Seppälä @ 2014-01-26 21:50 UTC (permalink / raw)
To: linux-media; +Cc: Mauro Carvalho Chehab, Sean Young, Antti Seppälä
This patch adds support for reading/writing wakeup samples via sysfs
to nuvoton-cir hardware.
The sysfs interface for nuvoton-cir contains raw IR pulse/space lengths.
If value is negative it is a space, otherwise it is a pulse.
Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
---
drivers/media/rc/nuvoton-cir.c | 118 +++++++++++++++++++++++++++++++++++++++++
drivers/media/rc/nuvoton-cir.h | 2 +
2 files changed, 120 insertions(+)
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 21ee0dc..015f3a8 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -531,6 +531,121 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
return 0;
}
+static int nvt_validate_wakeup_codes(struct list_head *wakeup_code_list)
+{
+ int i = 0;
+ const int MAX_SAMPLE = US_TO_NS(BUF_LEN_MASK * SAMPLE_PERIOD);
+ struct rc_wakeup_code *code;
+ list_for_each_entry(code, wakeup_code_list, list_item) {
+
+ /* Prevent writing too many or invalid codes */
+ if (++i > WAKE_FIFO_LEN)
+ return -EINVAL;
+ if (abs(code->value) > MAX_SAMPLE)
+ return -EINVAL;
+ }
+
+ return i;
+}
+
+static int nvt_wakeup_codes(struct rc_dev *dev,
+ struct list_head *wakeup_code_list, int write)
+{
+ int i = 0;
+ u8 cnt, val, reg, reg_learn_mode;
+ unsigned long flags;
+ struct rc_wakeup_code *code;
+ struct nvt_dev *nvt = dev->priv;
+
+ nvt_dbg_wake("%sing wakeup codes", write ? "writ" : "read");
+
+ if (write) {
+
+ /* Validate wake codes (count and values) */
+ i = nvt_validate_wakeup_codes(wakeup_code_list);
+ if (i < 0)
+ return -EINVAL;
+
+ reg = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON);
+ reg_learn_mode = reg & ~CIR_WAKE_IRCON_MODE0;
+ reg_learn_mode |= CIR_WAKE_IRCON_MODE1;
+
+ /* Lock the learn area to prevent racing with wake-isr */
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+
+ /* Enable fifo writes */
+ nvt_cir_wake_reg_write(nvt, reg_learn_mode, CIR_WAKE_IRCON);
+
+ /* Clear cir wake rx fifo */
+ nvt_clear_cir_wake_fifo(nvt);
+
+ pr_info("Wake samples (%d) =", i);
+
+ /* Write wake samples to fifo */
+ list_for_each_entry(code, wakeup_code_list, list_item) {
+
+ /* Convert to driver format */
+ val = DIV_ROUND_UP(abs(code->value), 1000L)
+ / SAMPLE_PERIOD;
+
+ if (code->value > 0)
+ val |= BUF_PULSE_BIT;
+
+ pr_cont(" %02x", val);
+ nvt_cir_wake_reg_write(nvt, val,
+ CIR_WAKE_WR_FIFO_DATA);
+ }
+ pr_cont("\n");
+
+ /* Switch cir to wakeup mode and disable fifo writing */
+ nvt_cir_wake_reg_write(nvt, reg, CIR_WAKE_IRCON);
+
+ /* Set number of bytes needed for wake */
+ nvt_cir_wake_reg_write(nvt, i ? i :
+ CIR_WAKE_FIFO_CMP_BYTES,
+ CIR_WAKE_FIFO_CMP_DEEP);
+
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+ } else {
+
+ /* Scroll to index 0 */
+ while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) {
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY);
+
+ /* Stuck index guardian */
+ if (++i > 255) {
+ nvt_dbg_wake("Idx reg is stuck!");
+ break;
+ }
+ }
+
+ /* Get size of wake fifo and allocate memory for the bytes */
+ cnt = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT);
+
+ for (i = 0; i < cnt; i++) {
+ code = kmalloc(sizeof(struct rc_wakeup_code),
+ GFP_KERNEL | GFP_ATOMIC);
+ if (!code)
+ return -ENOMEM;
+
+ val = nvt_cir_wake_reg_read(nvt,
+ CIR_WAKE_RD_FIFO_ONLY);
+
+ /* Convert to human readable sample-pulse format */
+ code->value = US_TO_NS((val & BUF_LEN_MASK)
+ * SAMPLE_PERIOD);
+ if (!(val & BUF_PULSE_BIT))
+ code->value *= -1;
+
+ list_add_tail(&code->list_item, wakeup_code_list);
+ }
+
+ return cnt;
+ }
+
+ return 0;
+}
/*
* nvt_tx_ir
*
@@ -1043,10 +1158,13 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
rdev->priv = nvt;
rdev->driver_type = RC_DRIVER_IR_RAW;
rdev->allowed_protos = RC_BIT_ALL;
+ rdev->allowed_wake_protos = RC_BIT_OTHER;
+ rdev->enabled_wake_protos = RC_BIT_OTHER;
rdev->open = nvt_open;
rdev->close = nvt_close;
rdev->tx_ir = nvt_tx_ir;
rdev->s_tx_carrier = nvt_set_tx_carrier;
+ rdev->s_wakeup_codes = nvt_wakeup_codes;
rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
rdev->input_phys = "nuvoton/cir0";
rdev->input_id.bustype = BUS_HOST;
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index 07e8310..24ff630 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -64,6 +64,8 @@ static int debug;
#define TX_BUF_LEN 256
#define RX_BUF_LEN 32
+#define WAKE_FIFO_LEN 67
+
struct nvt_dev {
struct pnp_dev *pdev;
struct rc_dev *rdev;
--
1.8.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread* [RFCv2 PATCH 5/5] winbond-cir: Add support for reading/writing wakeup scancodes via sysfs
2014-01-26 21:50 [RFCv2 PATCH 0/5] rc: Add generic sysfs interface for handling wakeup codes Antti Seppälä
` (3 preceding siblings ...)
2014-01-26 21:50 ` [RFCv2 PATCH 4/5] nuvoton-cir: Add support for reading/writing wakeup samples " Antti Seppälä
@ 2014-01-26 21:50 ` Antti Seppälä
2014-01-30 19:24 ` Sean Young
4 siblings, 1 reply; 8+ messages in thread
From: Antti Seppälä @ 2014-01-26 21:50 UTC (permalink / raw)
To: linux-media; +Cc: Mauro Carvalho Chehab, Sean Young, Antti Seppälä
This patch adds support for reading/writing wakeup scancodes via sysfs
to nuvoton-cir hardware.
The existing mechanism of setting wakeup scancodes by using module
parameters is left untouched. If set the module parameters function as
default values for sysfs files.
Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
---
drivers/media/rc/winbond-cir.c | 66 ++++++++++++++++++++++++++++++------------
1 file changed, 48 insertions(+), 18 deletions(-)
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 904baf4..c63a56e 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -683,6 +683,29 @@ wbcir_tx(struct rc_dev *dev, unsigned *b, unsigned count)
return count;
}
+static int wbcir_wakeup_codes(struct rc_dev *dev,
+ struct list_head *wakeup_code_list, int write)
+{
+ u32 value = 0x800F040C;
+ struct rc_wakeup_code *code;
+ if (write) {
+ code = list_first_entry_or_null(wakeup_code_list,
+ struct rc_wakeup_code,
+ list_item);
+ if (code)
+ value = code->value;
+
+ wake_sc = value;
+ } else {
+ code = kmalloc(sizeof(struct rc_wakeup_code), GFP_KERNEL);
+ if (!code)
+ return -ENOMEM;
+ code->value = wake_sc;
+ list_add_tail(&code->list_item, wakeup_code_list);
+ }
+ return 0;
+}
+
/*****************************************************************************
*
* SETUP/INIT/SUSPEND/RESUME FUNCTIONS
@@ -708,12 +731,11 @@ wbcir_shutdown(struct pnp_dev *device)
goto finish;
}
- switch (protocol) {
- case IR_PROTOCOL_RC5:
+ if (data->dev->enabled_wake_protos & RC_BIT_RC5) {
if (wake_sc > 0xFFF) {
do_wake = false;
dev_err(dev, "RC5 - Invalid wake scancode\n");
- break;
+ goto finish;
}
/* Mask = 13 bits, ex toggle */
@@ -726,13 +748,11 @@ wbcir_shutdown(struct pnp_dev *device)
if (!(wake_sc & 0x0040)) /* 2nd start bit */
match[1] |= 0x10;
- break;
-
- case IR_PROTOCOL_NEC:
+ } else if (data->dev->enabled_wake_protos & RC_BIT_NEC) {
if (wake_sc > 0xFFFFFF) {
do_wake = false;
dev_err(dev, "NEC - Invalid wake scancode\n");
- break;
+ goto finish;
}
mask[0] = mask[1] = mask[2] = mask[3] = 0xFF;
@@ -745,16 +765,12 @@ wbcir_shutdown(struct pnp_dev *device)
match[2] = bitrev8((wake_sc & 0xFF0000) >> 16);
else
match[2] = ~match[3];
-
- break;
-
- case IR_PROTOCOL_RC6:
-
+ } else if (data->dev->enabled_wake_protos & RC_BIT_RC6_0) {
if (wake_rc6mode == 0) {
if (wake_sc > 0xFFFF) {
do_wake = false;
dev_err(dev, "RC6 - Invalid wake scancode\n");
- break;
+ goto finish;
}
/* Command */
@@ -810,7 +826,7 @@ wbcir_shutdown(struct pnp_dev *device)
} else {
do_wake = false;
dev_err(dev, "RC6 - Invalid wake scancode\n");
- break;
+ goto finish;
}
/* Header */
@@ -824,11 +840,8 @@ wbcir_shutdown(struct pnp_dev *device)
dev_err(dev, "RC6 - Invalid wake mode\n");
}
- break;
-
- default:
+ } else {
do_wake = false;
- break;
}
finish:
@@ -1077,12 +1090,29 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
data->dev->s_carrier_report = wbcir_set_carrier_report;
data->dev->s_tx_mask = wbcir_txmask;
data->dev->s_tx_carrier = wbcir_txcarrier;
+ data->dev->s_wakeup_codes = wbcir_wakeup_codes;
data->dev->tx_ir = wbcir_tx;
data->dev->priv = data;
data->dev->dev.parent = &device->dev;
data->dev->timeout = MS_TO_NS(100);
data->dev->rx_resolution = US_TO_NS(2);
data->dev->allowed_protos = RC_BIT_ALL;
+ data->dev->allowed_wake_protos = RC_BIT_RC5 | RC_BIT_RC6_0 | RC_BIT_NEC;
+ /* Utilize default protocol from module parameter */
+ switch (protocol) {
+ case IR_PROTOCOL_RC5:
+ data->dev->enabled_wake_protos = RC_BIT_RC5;
+ break;
+ case IR_PROTOCOL_RC6:
+ data->dev->enabled_wake_protos = RC_BIT_RC6_0;
+ break;
+ case IR_PROTOCOL_NEC:
+ data->dev->enabled_wake_protos = RC_BIT_NEC;
+ break;
+ default:
+ data->dev->enabled_wake_protos = RC_BIT_NONE;
+ break;
+ }
err = rc_register_device(data->dev);
if (err)
--
1.8.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [RFCv2 PATCH 5/5] winbond-cir: Add support for reading/writing wakeup scancodes via sysfs
2014-01-26 21:50 ` [RFCv2 PATCH 5/5] winbond-cir: Add support for reading/writing wakeup scancodes " Antti Seppälä
@ 2014-01-30 19:24 ` Sean Young
2014-01-31 13:34 ` Antti Seppälä
0 siblings, 1 reply; 8+ messages in thread
From: Sean Young @ 2014-01-30 19:24 UTC (permalink / raw)
To: Antti Seppälä; +Cc: linux-media, Mauro Carvalho Chehab
On Sun, Jan 26, 2014 at 11:50:26PM +0200, Antti Seppälä wrote:
> This patch adds support for reading/writing wakeup scancodes via sysfs
> to nuvoton-cir hardware.
>
> The existing mechanism of setting wakeup scancodes by using module
> parameters is left untouched. If set the module parameters function as
> default values for sysfs files.
>
> Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
> ---
> drivers/media/rc/winbond-cir.c | 66 ++++++++++++++++++++++++++++++------------
> 1 file changed, 48 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
> index 904baf4..c63a56e 100644
> --- a/drivers/media/rc/winbond-cir.c
> +++ b/drivers/media/rc/winbond-cir.c
> @@ -683,6 +683,29 @@ wbcir_tx(struct rc_dev *dev, unsigned *b, unsigned count)
> return count;
> }
>
> +static int wbcir_wakeup_codes(struct rc_dev *dev,
> + struct list_head *wakeup_code_list, int write)
> +{
> + u32 value = 0x800F040C;
> + struct rc_wakeup_code *code;
> + if (write) {
I think it would be better to have a read/write function rather passing it
as an argument; they are distinct functions.
> + code = list_first_entry_or_null(wakeup_code_list,
> + struct rc_wakeup_code,
> + list_item);
> + if (code)
> + value = code->value;
If more than one value is provided then that should be an error; if no
value is provided then that is an error too. Sure the scancode can default
to mce sleep/rc6 on startup.
> +
> + wake_sc = value;
> + } else {
> + code = kmalloc(sizeof(struct rc_wakeup_code), GFP_KERNEL);
> + if (!code)
> + return -ENOMEM;
> + code->value = wake_sc;
> + list_add_tail(&code->list_item, wakeup_code_list);
> + }
> + return 0;
> +}
> +
> /*****************************************************************************
> *
> * SETUP/INIT/SUSPEND/RESUME FUNCTIONS
> @@ -708,12 +731,11 @@ wbcir_shutdown(struct pnp_dev *device)
> goto finish;
> }
>
> - switch (protocol) {
> - case IR_PROTOCOL_RC5:
> + if (data->dev->enabled_wake_protos & RC_BIT_RC5) {
> if (wake_sc > 0xFFF) {
> do_wake = false;
> dev_err(dev, "RC5 - Invalid wake scancode\n");
> - break;
> + goto finish;
> }
>
> /* Mask = 13 bits, ex toggle */
> @@ -726,13 +748,11 @@ wbcir_shutdown(struct pnp_dev *device)
> if (!(wake_sc & 0x0040)) /* 2nd start bit */
> match[1] |= 0x10;
>
> - break;
> -
> - case IR_PROTOCOL_NEC:
> + } else if (data->dev->enabled_wake_protos & RC_BIT_NEC) {
> if (wake_sc > 0xFFFFFF) {
> do_wake = false;
> dev_err(dev, "NEC - Invalid wake scancode\n");
> - break;
> + goto finish;
> }
>
> mask[0] = mask[1] = mask[2] = mask[3] = 0xFF;
> @@ -745,16 +765,12 @@ wbcir_shutdown(struct pnp_dev *device)
> match[2] = bitrev8((wake_sc & 0xFF0000) >> 16);
> else
> match[2] = ~match[3];
> -
> - break;
> -
> - case IR_PROTOCOL_RC6:
> -
> + } else if (data->dev->enabled_wake_protos & RC_BIT_RC6_0) {
> if (wake_rc6mode == 0) {
> if (wake_sc > 0xFFFF) {
> do_wake = false;
> dev_err(dev, "RC6 - Invalid wake scancode\n");
> - break;
> + goto finish;
> }
>
> /* Command */
> @@ -810,7 +826,7 @@ wbcir_shutdown(struct pnp_dev *device)
> } else {
> do_wake = false;
> dev_err(dev, "RC6 - Invalid wake scancode\n");
> - break;
> + goto finish;
> }
>
> /* Header */
> @@ -824,11 +840,8 @@ wbcir_shutdown(struct pnp_dev *device)
> dev_err(dev, "RC6 - Invalid wake mode\n");
> }
>
> - break;
> -
> - default:
> + } else {
> do_wake = false;
> - break;
> }
>
> finish:
> @@ -1077,12 +1090,29 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
> data->dev->s_carrier_report = wbcir_set_carrier_report;
> data->dev->s_tx_mask = wbcir_txmask;
> data->dev->s_tx_carrier = wbcir_txcarrier;
> + data->dev->s_wakeup_codes = wbcir_wakeup_codes;
> data->dev->tx_ir = wbcir_tx;
> data->dev->priv = data;
> data->dev->dev.parent = &device->dev;
> data->dev->timeout = MS_TO_NS(100);
> data->dev->rx_resolution = US_TO_NS(2);
> data->dev->allowed_protos = RC_BIT_ALL;
> + data->dev->allowed_wake_protos = RC_BIT_RC5 | RC_BIT_RC6_0 | RC_BIT_NEC;
> + /* Utilize default protocol from module parameter */
> + switch (protocol) {
> + case IR_PROTOCOL_RC5:
> + data->dev->enabled_wake_protos = RC_BIT_RC5;
> + break;
> + case IR_PROTOCOL_RC6:
> + data->dev->enabled_wake_protos = RC_BIT_RC6_0;
> + break;
> + case IR_PROTOCOL_NEC:
> + data->dev->enabled_wake_protos = RC_BIT_NEC;
> + break;
> + default:
> + data->dev->enabled_wake_protos = RC_BIT_NONE;
> + break;
> + }
You might as well remove the module parameters, I'd say.
>
> err = rc_register_device(data->dev);
> if (err)
> --
> 1.8.3.2
Sean
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [RFCv2 PATCH 5/5] winbond-cir: Add support for reading/writing wakeup scancodes via sysfs
2014-01-30 19:24 ` Sean Young
@ 2014-01-31 13:34 ` Antti Seppälä
0 siblings, 0 replies; 8+ messages in thread
From: Antti Seppälä @ 2014-01-31 13:34 UTC (permalink / raw)
To: Sean Young; +Cc: linux-media, Mauro Carvalho Chehab
On 30 January 2014 21:24, Sean Young <sean@mess.org> wrote:
> On Sun, Jan 26, 2014 at 11:50:26PM +0200, Antti Seppälä wrote:
>> This patch adds support for reading/writing wakeup scancodes via sysfs
>> to nuvoton-cir hardware.
>>
>> The existing mechanism of setting wakeup scancodes by using module
>> parameters is left untouched. If set the module parameters function as
>> default values for sysfs files.
>>
>> Signed-off-by: Antti Seppälä <a.seppala@gmail.com>
>> ---
>> drivers/media/rc/winbond-cir.c | 66 ++++++++++++++++++++++++++++++------------
>> 1 file changed, 48 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
>> index 904baf4..c63a56e 100644
>> --- a/drivers/media/rc/winbond-cir.c
>> +++ b/drivers/media/rc/winbond-cir.c
>> @@ -683,6 +683,29 @@ wbcir_tx(struct rc_dev *dev, unsigned *b, unsigned count)
>> return count;
>> }
>>
>> +static int wbcir_wakeup_codes(struct rc_dev *dev,
>> + struct list_head *wakeup_code_list, int write)
>> +{
>> + u32 value = 0x800F040C;
>> + struct rc_wakeup_code *code;
>> + if (write) {
>
> I think it would be better to have a read/write function rather passing it
> as an argument; they are distinct functions.
>
I modeled the wakeup code callback after other s_* callbacks found in rc-core
some of which have similar kind of enable/disable type flag.
I guess I can split the callback into a more readable version at the expense of
some added code lines in each driver.
>> + code = list_first_entry_or_null(wakeup_code_list,
>> + struct rc_wakeup_code,
>> + list_item);
>> + if (code)
>> + value = code->value;
>
> If more than one value is provided then that should be an error; if no
> value is provided then that is an error too. Sure the scancode can default
> to mce sleep/rc6 on startup.
>
I'll add stricter sanity checking here.
>> +
>> + wake_sc = value;
>> + } else {
>> + code = kmalloc(sizeof(struct rc_wakeup_code), GFP_KERNEL);
>> + if (!code)
>> + return -ENOMEM;
>> + code->value = wake_sc;
>> + list_add_tail(&code->list_item, wakeup_code_list);
>> + }
>> + return 0;
>> +}
>> +
>> /*****************************************************************************
>> *
>> * SETUP/INIT/SUSPEND/RESUME FUNCTIONS
>> @@ -708,12 +731,11 @@ wbcir_shutdown(struct pnp_dev *device)
>> goto finish;
>> }
>>
>> - switch (protocol) {
>> - case IR_PROTOCOL_RC5:
>> + if (data->dev->enabled_wake_protos & RC_BIT_RC5) {
>> if (wake_sc > 0xFFF) {
>> do_wake = false;
>> dev_err(dev, "RC5 - Invalid wake scancode\n");
>> - break;
>> + goto finish;
>> }
>>
>> /* Mask = 13 bits, ex toggle */
>> @@ -726,13 +748,11 @@ wbcir_shutdown(struct pnp_dev *device)
>> if (!(wake_sc & 0x0040)) /* 2nd start bit */
>> match[1] |= 0x10;
>>
>> - break;
>> -
>> - case IR_PROTOCOL_NEC:
>> + } else if (data->dev->enabled_wake_protos & RC_BIT_NEC) {
>> if (wake_sc > 0xFFFFFF) {
>> do_wake = false;
>> dev_err(dev, "NEC - Invalid wake scancode\n");
>> - break;
>> + goto finish;
>> }
>>
>> mask[0] = mask[1] = mask[2] = mask[3] = 0xFF;
>> @@ -745,16 +765,12 @@ wbcir_shutdown(struct pnp_dev *device)
>> match[2] = bitrev8((wake_sc & 0xFF0000) >> 16);
>> else
>> match[2] = ~match[3];
>> -
>> - break;
>> -
>> - case IR_PROTOCOL_RC6:
>> -
>> + } else if (data->dev->enabled_wake_protos & RC_BIT_RC6_0) {
>> if (wake_rc6mode == 0) {
>> if (wake_sc > 0xFFFF) {
>> do_wake = false;
>> dev_err(dev, "RC6 - Invalid wake scancode\n");
>> - break;
>> + goto finish;
>> }
>>
>> /* Command */
>> @@ -810,7 +826,7 @@ wbcir_shutdown(struct pnp_dev *device)
>> } else {
>> do_wake = false;
>> dev_err(dev, "RC6 - Invalid wake scancode\n");
>> - break;
>> + goto finish;
>> }
>>
>> /* Header */
>> @@ -824,11 +840,8 @@ wbcir_shutdown(struct pnp_dev *device)
>> dev_err(dev, "RC6 - Invalid wake mode\n");
>> }
>>
>> - break;
>> -
>> - default:
>> + } else {
>> do_wake = false;
>> - break;
>> }
>>
>> finish:
>> @@ -1077,12 +1090,29 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
>> data->dev->s_carrier_report = wbcir_set_carrier_report;
>> data->dev->s_tx_mask = wbcir_txmask;
>> data->dev->s_tx_carrier = wbcir_txcarrier;
>> + data->dev->s_wakeup_codes = wbcir_wakeup_codes;
>> data->dev->tx_ir = wbcir_tx;
>> data->dev->priv = data;
>> data->dev->dev.parent = &device->dev;
>> data->dev->timeout = MS_TO_NS(100);
>> data->dev->rx_resolution = US_TO_NS(2);
>> data->dev->allowed_protos = RC_BIT_ALL;
>> + data->dev->allowed_wake_protos = RC_BIT_RC5 | RC_BIT_RC6_0 | RC_BIT_NEC;
>> + /* Utilize default protocol from module parameter */
>> + switch (protocol) {
>> + case IR_PROTOCOL_RC5:
>> + data->dev->enabled_wake_protos = RC_BIT_RC5;
>> + break;
>> + case IR_PROTOCOL_RC6:
>> + data->dev->enabled_wake_protos = RC_BIT_RC6_0;
>> + break;
>> + case IR_PROTOCOL_NEC:
>> + data->dev->enabled_wake_protos = RC_BIT_NEC;
>> + break;
>> + default:
>> + data->dev->enabled_wake_protos = RC_BIT_NONE;
>> + break;
>> + }
>
> You might as well remove the module parameters, I'd say.
>
I can add a patch removing all the other wake_* parameters but it seems
that wake_rc6mode needs to stay.
This is because the wakeup_protocols file (or protocols for that matter) is not
able to differentiate between rc6 and rc6a and this distinction is needed for
wakeup in winbond-cir.
-Antti
^ permalink raw reply [flat|nested] 8+ messages in thread