Commit da6e162d authored by David Härdeman's avatar David Härdeman Committed by Mauro Carvalho Chehab

[media] rc-core: simplify sysfs code

Simplify and cleanup the sysfs code a bit.

[m.chehab@samsung.com: rebased and fixed a CodingStyle issue]
Signed-off-by: default avatarDavid Härdeman <david@hardeman.nu>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent 0bc56cbe
...@@ -240,6 +240,12 @@ ir_raw_get_allowed_protocols(void) ...@@ -240,6 +240,12 @@ ir_raw_get_allowed_protocols(void)
return protocols; return protocols;
} }
static int change_protocol(struct rc_dev *dev, u64 *rc_type)
{
/* the caller will update dev->enabled_protocols */
return 0;
}
/* /*
* Used to (un)register raw event clients * Used to (un)register raw event clients
*/ */
...@@ -257,6 +263,7 @@ int ir_raw_event_register(struct rc_dev *dev) ...@@ -257,6 +263,7 @@ int ir_raw_event_register(struct rc_dev *dev)
dev->raw->dev = dev; dev->raw->dev = dev;
rc_set_enabled_protocols(dev, ~0); rc_set_enabled_protocols(dev, ~0);
dev->change_protocol = change_protocol;
rc = kfifo_alloc(&dev->raw->kfifo, rc = kfifo_alloc(&dev->raw->kfifo,
sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE, sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
GFP_KERNEL); GFP_KERNEL);
......
...@@ -830,7 +830,7 @@ struct rc_filter_attribute { ...@@ -830,7 +830,7 @@ struct rc_filter_attribute {
/** /**
* show_protocols() - shows the current/wakeup IR protocol(s) * show_protocols() - shows the current/wakeup IR protocol(s)
* @device: the device descriptor * @device: the device descriptor
* @mattr: the device attribute struct (unused) * @mattr: the device attribute struct
* @buf: a pointer to the output buffer * @buf: a pointer to the output buffer
* *
* This routine is a callback routine for input read the IR protocol type(s). * This routine is a callback routine for input read the IR protocol type(s).
...@@ -856,20 +856,21 @@ static ssize_t show_protocols(struct device *device, ...@@ -856,20 +856,21 @@ static ssize_t show_protocols(struct device *device,
mutex_lock(&dev->lock); mutex_lock(&dev->lock);
enabled = dev->enabled_protocols[fattr->type]; if (fattr->type == RC_FILTER_NORMAL) {
if (dev->driver_type == RC_DRIVER_SCANCODE || enabled = dev->enabled_protocols[RC_FILTER_NORMAL];
fattr->type == RC_FILTER_WAKEUP) if (dev->raw)
allowed = dev->allowed_protocols[fattr->type];
else if (dev->raw)
allowed = ir_raw_get_allowed_protocols(); allowed = ir_raw_get_allowed_protocols();
else { else
mutex_unlock(&dev->lock); allowed = dev->allowed_protocols[RC_FILTER_NORMAL];
return -ENODEV; } else {
enabled = dev->enabled_protocols[RC_FILTER_WAKEUP];
allowed = dev->allowed_protocols[RC_FILTER_WAKEUP];
} }
IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", mutex_unlock(&dev->lock);
(long long)allowed,
(long long)enabled); IR_dprintk(1, "%s: allowed - 0x%llx, enabled - 0x%llx\n",
__func__, (long long)allowed, (long long)enabled);
for (i = 0; i < ARRAY_SIZE(proto_names); i++) { for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
if (allowed & enabled & proto_names[i].type) if (allowed & enabled & proto_names[i].type)
...@@ -885,62 +886,29 @@ static ssize_t show_protocols(struct device *device, ...@@ -885,62 +886,29 @@ static ssize_t show_protocols(struct device *device,
tmp--; tmp--;
*tmp = '\n'; *tmp = '\n';
mutex_unlock(&dev->lock);
return tmp + 1 - buf; return tmp + 1 - buf;
} }
/** /**
* store_protocols() - changes the current/wakeup IR protocol(s) * parse_protocol_change() - parses a protocol change request
* @device: the device descriptor * @protocols: pointer to the bitmask of current protocols
* @mattr: the device attribute struct (unused) * @buf: pointer to the buffer with a list of changes
* @buf: a pointer to the input buffer
* @len: length of the input buffer
* *
* This routine is for changing the IR protocol type. * Writing "+proto" will add a protocol to the protocol mask.
* It is trigged by writing to /sys/class/rc/rc?/[wakeup_]protocols. * Writing "-proto" will remove a protocol from protocol mask.
* Writing "+proto" will add a protocol to the list of enabled protocols.
* Writing "-proto" will remove a protocol from the list of enabled protocols.
* Writing "proto" will enable only "proto". * Writing "proto" will enable only "proto".
* Writing "none" will disable all protocols. * Writing "none" will disable all protocols.
* Returns -EINVAL if an invalid protocol combination or unknown protocol name * Returns the number of changes performed or a negative error code.
* is used, otherwise @len.
*
* dev->lock is taken to guard against races between device
* registration, store_protocols and show_protocols.
*/ */
static ssize_t store_protocols(struct device *device, static int parse_protocol_change(u64 *protocols, const char *buf)
struct device_attribute *mattr,
const char *data,
size_t len)
{ {
struct rc_dev *dev = to_rc_dev(device);
struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr);
bool enable, disable;
const char *tmp; const char *tmp;
u64 old_type, type; unsigned count = 0;
bool enable, disable;
u64 mask; u64 mask;
int rc, i, count = 0; int i;
ssize_t ret;
int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
struct rc_scancode_filter local_filter, *filter;
/* Device is being removed */
if (!dev)
return -EINVAL;
mutex_lock(&dev->lock);
if (dev->driver_type != RC_DRIVER_SCANCODE && !dev->raw) {
IR_dprintk(1, "Protocol switching not supported\n");
ret = -EINVAL;
goto out;
}
old_type = dev->enabled_protocols[fattr->type];
type = old_type;
while ((tmp = strsep((char **) &data, " \n")) != NULL) { while ((tmp = strsep((char **)&buf, " \n")) != NULL) {
if (!*tmp) if (!*tmp)
break; break;
...@@ -966,76 +934,124 @@ static ssize_t store_protocols(struct device *device, ...@@ -966,76 +934,124 @@ static ssize_t store_protocols(struct device *device,
if (i == ARRAY_SIZE(proto_names)) { if (i == ARRAY_SIZE(proto_names)) {
IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
ret = -EINVAL; return -EINVAL;
goto out;
} }
count++; count++;
if (enable) if (enable)
type |= mask; *protocols |= mask;
else if (disable) else if (disable)
type &= ~mask; *protocols &= ~mask;
else else
type = mask; *protocols = mask;
} }
if (!count) { if (!count) {
IR_dprintk(1, "Protocol not specified\n"); IR_dprintk(1, "Protocol not specified\n");
ret = -EINVAL; return -EINVAL;
goto out; }
return count;
}
/**
* store_protocols() - changes the current/wakeup IR protocol(s)
* @device: the device descriptor
* @mattr: the device attribute struct
* @buf: a pointer to the input buffer
* @len: length of the input buffer
*
* This routine is for changing the IR protocol type.
* It is trigged by writing to /sys/class/rc/rc?/[wakeup_]protocols.
* See parse_protocol_change() for the valid commands.
* Returns @len on success or a negative error code.
*
* dev->lock is taken to guard against races between device
* registration, store_protocols and show_protocols.
*/
static ssize_t store_protocols(struct device *device,
struct device_attribute *mattr,
const char *buf, size_t len)
{
struct rc_dev *dev = to_rc_dev(device);
struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr);
u64 *current_protocols;
int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
struct rc_scancode_filter *filter;
int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
u64 old_protocols, new_protocols;
ssize_t rc;
/* Device is being removed */
if (!dev)
return -EINVAL;
if (fattr->type == RC_FILTER_NORMAL) {
IR_dprintk(1, "Normal protocol change requested\n");
current_protocols = &dev->enabled_protocols[RC_FILTER_NORMAL];
change_protocol = dev->change_protocol;
filter = &dev->scancode_filters[RC_FILTER_NORMAL];
set_filter = dev->s_filter;
} else {
IR_dprintk(1, "Wakeup protocol change requested\n");
current_protocols = &dev->enabled_protocols[RC_FILTER_WAKEUP];
change_protocol = dev->change_wakeup_protocol;
filter = &dev->scancode_filters[RC_FILTER_WAKEUP];
set_filter = dev->s_wakeup_filter;
} }
change_protocol = (fattr->type == RC_FILTER_NORMAL) if (!change_protocol) {
? dev->change_protocol : dev->change_wakeup_protocol; IR_dprintk(1, "Protocol switching not supported\n");
if (change_protocol) { return -EINVAL;
rc = change_protocol(dev, &type); }
mutex_lock(&dev->lock);
old_protocols = *current_protocols;
new_protocols = old_protocols;
rc = parse_protocol_change(&new_protocols, buf);
if (rc < 0)
goto out;
rc = change_protocol(dev, &new_protocols);
if (rc < 0) { if (rc < 0) {
IR_dprintk(1, "Error setting protocols to 0x%llx\n", IR_dprintk(1, "Error setting protocols to 0x%llx\n",
(long long)type); (long long)new_protocols);
ret = -EINVAL;
goto out; goto out;
} }
if (new_protocols == old_protocols) {
rc = len;
goto out;
} }
dev->enabled_protocols[fattr->type] = type; *current_protocols = new_protocols;
IR_dprintk(1, "Current protocol(s): 0x%llx\n", IR_dprintk(1, "Protocols changed to 0x%llx\n", (long long)new_protocols);
(long long)type);
/* /*
* If the protocol is changed the filter needs updating. * If the protocol is changed the filter needs updating.
* Try setting the same filter with the new protocol (if any). * Try setting the same filter with the new protocol (if any).
* Fall back to clearing the filter. * Fall back to clearing the filter.
*/ */
filter = &dev->scancode_filters[fattr->type]; if (set_filter && filter->mask) {
set_filter = (fattr->type == RC_FILTER_NORMAL) if (new_protocols)
? dev->s_filter : dev->s_wakeup_filter; rc = set_filter(dev, filter);
else
if (set_filter && old_type != type && filter->mask) { rc = -1;
local_filter = *filter;
if (!type) {
/* no protocol => clear filter */
ret = -1;
} else {
/* hardware filtering => try setting, otherwise clear */
ret = set_filter(dev, &local_filter);
}
if (ret < 0) {
/* clear the filter */
local_filter.data = 0;
local_filter.mask = 0;
set_filter(dev, &local_filter);
}
/* commit the new filter */ if (rc < 0) {
*filter = local_filter; filter->data = 0;
filter->mask = 0;
set_filter(dev, filter);
}
} }
ret = len; rc = len;
out: out:
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
return ret; return rc;
} }
/** /**
...@@ -1061,20 +1077,23 @@ static ssize_t show_filter(struct device *device, ...@@ -1061,20 +1077,23 @@ static ssize_t show_filter(struct device *device,
{ {
struct rc_dev *dev = to_rc_dev(device); struct rc_dev *dev = to_rc_dev(device);
struct rc_filter_attribute *fattr = to_rc_filter_attr(attr); struct rc_filter_attribute *fattr = to_rc_filter_attr(attr);
struct rc_scancode_filter *filter;
u32 val; u32 val;
/* Device is being removed */ /* Device is being removed */
if (!dev) if (!dev)
return -EINVAL; return -EINVAL;
if (fattr->type == RC_FILTER_NORMAL)
filter = &dev->scancode_filters[RC_FILTER_NORMAL];
else
filter = &dev->scancode_filters[RC_FILTER_WAKEUP];
mutex_lock(&dev->lock); mutex_lock(&dev->lock);
if ((fattr->type == RC_FILTER_NORMAL && !dev->s_filter) || if (fattr->mask)
(fattr->type == RC_FILTER_WAKEUP && !dev->s_wakeup_filter)) val = filter->mask;
val = 0;
else if (fattr->mask)
val = dev->scancode_filters[fattr->type].mask;
else else
val = dev->scancode_filters[fattr->type].data; val = filter->data;
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
return sprintf(buf, "%#x\n", val); return sprintf(buf, "%#x\n", val);
...@@ -1101,15 +1120,15 @@ static ssize_t show_filter(struct device *device, ...@@ -1101,15 +1120,15 @@ static ssize_t show_filter(struct device *device,
*/ */
static ssize_t store_filter(struct device *device, static ssize_t store_filter(struct device *device,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, const char *buf, size_t len)
size_t count)
{ {
struct rc_dev *dev = to_rc_dev(device); struct rc_dev *dev = to_rc_dev(device);
struct rc_filter_attribute *fattr = to_rc_filter_attr(attr); struct rc_filter_attribute *fattr = to_rc_filter_attr(attr);
struct rc_scancode_filter local_filter, *filter; struct rc_scancode_filter new_filter, *filter;
int ret; int ret;
unsigned long val; unsigned long val;
int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter); int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
u64 *enabled_protocols;
/* Device is being removed */ /* Device is being removed */
if (!dev) if (!dev)
...@@ -1119,38 +1138,42 @@ static ssize_t store_filter(struct device *device, ...@@ -1119,38 +1138,42 @@ static ssize_t store_filter(struct device *device,
if (ret < 0) if (ret < 0)
return ret; return ret;
/* Can the scancode filter be set? */ if (fattr->type == RC_FILTER_NORMAL) {
set_filter = (fattr->type == RC_FILTER_NORMAL) ? dev->s_filter : set_filter = dev->s_filter;
dev->s_wakeup_filter; enabled_protocols = &dev->enabled_protocols[RC_FILTER_NORMAL];
filter = &dev->scancode_filters[RC_FILTER_NORMAL];
} else {
set_filter = dev->s_wakeup_filter;
enabled_protocols = &dev->enabled_protocols[RC_FILTER_WAKEUP];
filter = &dev->scancode_filters[RC_FILTER_WAKEUP];
}
if (!set_filter) if (!set_filter)
return -EINVAL; return -EINVAL;
mutex_lock(&dev->lock); mutex_lock(&dev->lock);
/* Tell the driver about the new filter */ new_filter = *filter;
filter = &dev->scancode_filters[fattr->type];
local_filter = *filter;
if (fattr->mask) if (fattr->mask)
local_filter.mask = val; new_filter.mask = val;
else else
local_filter.data = val; new_filter.data = val;
if (!dev->enabled_protocols[fattr->type] && local_filter.mask) { if (!*enabled_protocols && val) {
/* refuse to set a filter unless a protocol is enabled */ /* refuse to set a filter unless a protocol is enabled */
ret = -EINVAL; ret = -EINVAL;
goto unlock; goto unlock;
} }
ret = set_filter(dev, &local_filter); ret = set_filter(dev, &new_filter);
if (ret < 0) if (ret < 0)
goto unlock; goto unlock;
/* Success, commit the new filter */ *filter = new_filter;
*filter = local_filter;
unlock: unlock:
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
return (ret < 0) ? ret : count; return (ret < 0) ? ret : len;
} }
static void rc_dev_release(struct device *device) static void rc_dev_release(struct device *device)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment