@@ -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",
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(-)