diff options
Diffstat (limited to 'drivers/media/IR/ir-sysfs.c')
| -rw-r--r-- | drivers/media/IR/ir-sysfs.c | 251 |
1 files changed, 143 insertions, 108 deletions
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c index 2098dd1488e..6273047e915 100644 --- a/drivers/media/IR/ir-sysfs.c +++ b/drivers/media/IR/ir-sysfs.c | |||
| @@ -33,125 +33,172 @@ static struct class ir_input_class = { | |||
| 33 | .devnode = ir_devnode, | 33 | .devnode = ir_devnode, |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | static struct { | ||
| 37 | u64 type; | ||
| 38 | char *name; | ||
| 39 | } proto_names[] = { | ||
| 40 | { IR_TYPE_UNKNOWN, "unknown" }, | ||
| 41 | { IR_TYPE_RC5, "rc-5" }, | ||
| 42 | { IR_TYPE_NEC, "nec" }, | ||
| 43 | { IR_TYPE_RC6, "rc-6" }, | ||
| 44 | { IR_TYPE_JVC, "jvc" }, | ||
| 45 | { IR_TYPE_SONY, "sony" }, | ||
| 46 | { IR_TYPE_LIRC, "lirc" }, | ||
| 47 | }; | ||
| 48 | |||
| 49 | #define PROTO_NONE "none" | ||
| 50 | |||
| 36 | /** | 51 | /** |
| 37 | * show_protocol() - shows the current IR protocol | 52 | * show_protocols() - shows the current IR protocol(s) |
| 38 | * @d: the device descriptor | 53 | * @d: the device descriptor |
| 39 | * @mattr: the device attribute struct (unused) | 54 | * @mattr: the device attribute struct (unused) |
| 40 | * @buf: a pointer to the output buffer | 55 | * @buf: a pointer to the output buffer |
| 41 | * | 56 | * |
| 42 | * This routine is a callback routine for input read the IR protocol type. | 57 | * This routine is a callback routine for input read the IR protocol type(s). |
| 43 | * it is trigged by reading /sys/class/rc/rc?/current_protocol. | 58 | * it is trigged by reading /sys/class/rc/rc?/protocols. |
| 44 | * It returns the protocol name, as understood by the driver. | 59 | * It returns the protocol names of supported protocols. |
| 60 | * Enabled protocols are printed in brackets. | ||
| 45 | */ | 61 | */ |
| 46 | static ssize_t show_protocol(struct device *d, | 62 | static ssize_t show_protocols(struct device *d, |
| 47 | struct device_attribute *mattr, char *buf) | 63 | struct device_attribute *mattr, char *buf) |
| 48 | { | 64 | { |
| 49 | char *s; | ||
| 50 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); | 65 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); |
| 51 | u64 ir_type = ir_dev->rc_tab.ir_type; | 66 | u64 allowed, enabled; |
| 52 | 67 | char *tmp = buf; | |
| 53 | IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type); | 68 | int i; |
| 54 | 69 | ||
| 55 | /* FIXME: doesn't support multiple protocols at the same time */ | 70 | if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) { |
| 56 | if (ir_type == IR_TYPE_UNKNOWN) | 71 | enabled = ir_dev->rc_tab.ir_type; |
| 57 | s = "Unknown"; | 72 | allowed = ir_dev->props->allowed_protos; |
| 58 | else if (ir_type == IR_TYPE_RC5) | 73 | } else { |
| 59 | s = "rc-5"; | 74 | enabled = ir_dev->raw->enabled_protocols; |
| 60 | else if (ir_type == IR_TYPE_NEC) | 75 | allowed = ir_raw_get_allowed_protocols(); |
| 61 | s = "nec"; | 76 | } |
| 62 | else if (ir_type == IR_TYPE_RC6) | 77 | |
| 63 | s = "rc6"; | 78 | IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", |
| 64 | else if (ir_type == IR_TYPE_JVC) | 79 | (long long)allowed, |
| 65 | s = "jvc"; | 80 | (long long)enabled); |
| 66 | else if (ir_type == IR_TYPE_SONY) | ||
| 67 | s = "sony"; | ||
| 68 | else | ||
| 69 | s = "other"; | ||
| 70 | 81 | ||
| 71 | return sprintf(buf, "%s\n", s); | 82 | for (i = 0; i < ARRAY_SIZE(proto_names); i++) { |
| 83 | if (allowed & enabled & proto_names[i].type) | ||
| 84 | tmp += sprintf(tmp, "[%s] ", proto_names[i].name); | ||
| 85 | else if (allowed & proto_names[i].type) | ||
| 86 | tmp += sprintf(tmp, "%s ", proto_names[i].name); | ||
| 87 | } | ||
| 88 | |||
| 89 | if (tmp != buf) | ||
| 90 | tmp--; | ||
| 91 | *tmp = '\n'; | ||
| 92 | return tmp + 1 - buf; | ||
| 72 | } | 93 | } |
| 73 | 94 | ||
| 74 | /** | 95 | /** |
| 75 | * store_protocol() - shows the current IR protocol | 96 | * store_protocols() - changes the current IR protocol(s) |
| 76 | * @d: the device descriptor | 97 | * @d: the device descriptor |
| 77 | * @mattr: the device attribute struct (unused) | 98 | * @mattr: the device attribute struct (unused) |
| 78 | * @buf: a pointer to the input buffer | 99 | * @buf: a pointer to the input buffer |
| 79 | * @len: length of the input buffer | 100 | * @len: length of the input buffer |
| 80 | * | 101 | * |
| 81 | * This routine is a callback routine for changing the IR protocol type. | 102 | * This routine is a callback routine for changing the IR protocol type. |
| 82 | * it is trigged by reading /sys/class/rc/rc?/current_protocol. | 103 | * It is trigged by writing to /sys/class/rc/rc?/protocols. |
| 83 | * It changes the IR the protocol name, if the IR type is recognized | 104 | * Writing "+proto" will add a protocol to the list of enabled protocols. |
| 84 | * by the driver. | 105 | * Writing "-proto" will remove a protocol from the list of enabled protocols. |
| 85 | * If an unknown protocol name is used, returns -EINVAL. | 106 | * Writing "proto" will enable only "proto". |
| 107 | * Writing "none" will disable all protocols. | ||
| 108 | * Returns -EINVAL if an invalid protocol combination or unknown protocol name | ||
| 109 | * is used, otherwise @len. | ||
| 86 | */ | 110 | */ |
| 87 | static ssize_t store_protocol(struct device *d, | 111 | static ssize_t store_protocols(struct device *d, |
| 88 | struct device_attribute *mattr, | 112 | struct device_attribute *mattr, |
| 89 | const char *data, | 113 | const char *data, |
| 90 | size_t len) | 114 | size_t len) |
| 91 | { | 115 | { |
| 92 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); | 116 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); |
| 93 | u64 ir_type = 0; | 117 | bool enable, disable; |
| 94 | int rc = -EINVAL; | 118 | const char *tmp; |
| 119 | u64 type; | ||
| 120 | u64 mask; | ||
| 121 | int rc, i, count = 0; | ||
| 95 | unsigned long flags; | 122 | unsigned long flags; |
| 96 | char *buf; | 123 | |
| 97 | 124 | if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) | |
| 98 | while ((buf = strsep((char **) &data, " \n")) != NULL) { | 125 | type = ir_dev->rc_tab.ir_type; |
| 99 | if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5")) | 126 | else |
| 100 | ir_type |= IR_TYPE_RC5; | 127 | type = ir_dev->raw->enabled_protocols; |
| 101 | if (!strcasecmp(buf, "nec")) | 128 | |
| 102 | ir_type |= IR_TYPE_NEC; | 129 | while ((tmp = strsep((char **) &data, " \n")) != NULL) { |
| 103 | if (!strcasecmp(buf, "jvc")) | 130 | if (!*tmp) |
| 104 | ir_type |= IR_TYPE_JVC; | 131 | break; |
| 105 | if (!strcasecmp(buf, "sony")) | 132 | |
| 106 | ir_type |= IR_TYPE_SONY; | 133 | if (*tmp == '+') { |
| 134 | enable = true; | ||
| 135 | disable = false; | ||
| 136 | tmp++; | ||
| 137 | } else if (*tmp == '-') { | ||
| 138 | enable = false; | ||
| 139 | disable = true; | ||
| 140 | tmp++; | ||
| 141 | } else { | ||
| 142 | enable = false; | ||
| 143 | disable = false; | ||
| 144 | } | ||
| 145 | |||
| 146 | if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) { | ||
| 147 | tmp += sizeof(PROTO_NONE); | ||
| 148 | mask = 0; | ||
| 149 | count++; | ||
| 150 | } else { | ||
| 151 | for (i = 0; i < ARRAY_SIZE(proto_names); i++) { | ||
| 152 | if (!strncasecmp(tmp, proto_names[i].name, strlen(proto_names[i].name))) { | ||
| 153 | tmp += strlen(proto_names[i].name); | ||
| 154 | mask = proto_names[i].type; | ||
| 155 | break; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | if (i == ARRAY_SIZE(proto_names)) { | ||
| 159 | IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); | ||
| 160 | return -EINVAL; | ||
| 161 | } | ||
| 162 | count++; | ||
| 163 | } | ||
| 164 | |||
| 165 | if (enable) | ||
| 166 | type |= mask; | ||
| 167 | else if (disable) | ||
| 168 | type &= ~mask; | ||
| 169 | else | ||
| 170 | type = mask; | ||
| 107 | } | 171 | } |
| 108 | 172 | ||
| 109 | if (!ir_type) { | 173 | if (!count) { |
| 110 | IR_dprintk(1, "Unknown protocol\n"); | 174 | IR_dprintk(1, "Protocol not specified\n"); |
| 111 | return -EINVAL; | 175 | return -EINVAL; |
| 112 | } | 176 | } |
| 113 | 177 | ||
| 114 | if (ir_dev->props && ir_dev->props->change_protocol) | 178 | if (ir_dev->props && ir_dev->props->change_protocol) { |
| 115 | rc = ir_dev->props->change_protocol(ir_dev->props->priv, | 179 | rc = ir_dev->props->change_protocol(ir_dev->props->priv, |
| 116 | ir_type); | 180 | type); |
| 117 | 181 | if (rc < 0) { | |
| 118 | if (rc < 0) { | 182 | IR_dprintk(1, "Error setting protocols to 0x%llx\n", |
| 119 | IR_dprintk(1, "Error setting protocol to %lld\n", | 183 | (long long)type); |
| 120 | (long long)ir_type); | 184 | return -EINVAL; |
| 121 | return -EINVAL; | 185 | } |
| 122 | } | 186 | } |
| 123 | 187 | ||
| 124 | spin_lock_irqsave(&ir_dev->rc_tab.lock, flags); | 188 | if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) { |
| 125 | ir_dev->rc_tab.ir_type = ir_type; | 189 | spin_lock_irqsave(&ir_dev->rc_tab.lock, flags); |
| 126 | spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags); | 190 | ir_dev->rc_tab.ir_type = type; |
| 191 | spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags); | ||
| 192 | } else { | ||
| 193 | ir_dev->raw->enabled_protocols = type; | ||
| 194 | } | ||
| 127 | 195 | ||
| 128 | IR_dprintk(1, "Current protocol(s) is(are) %lld\n", | 196 | IR_dprintk(1, "Current protocol(s): 0x%llx\n", |
| 129 | (long long)ir_type); | 197 | (long long)type); |
| 130 | 198 | ||
| 131 | return len; | 199 | return len; |
| 132 | } | 200 | } |
| 133 | 201 | ||
| 134 | static ssize_t show_supported_protocols(struct device *d, | ||
| 135 | struct device_attribute *mattr, char *buf) | ||
| 136 | { | ||
| 137 | char *orgbuf = buf; | ||
| 138 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); | ||
| 139 | |||
| 140 | /* FIXME: doesn't support multiple protocols at the same time */ | ||
| 141 | if (ir_dev->props->allowed_protos == IR_TYPE_UNKNOWN) | ||
| 142 | buf += sprintf(buf, "unknown "); | ||
| 143 | if (ir_dev->props->allowed_protos & IR_TYPE_RC5) | ||
| 144 | buf += sprintf(buf, "rc-5 "); | ||
| 145 | if (ir_dev->props->allowed_protos & IR_TYPE_NEC) | ||
| 146 | buf += sprintf(buf, "nec "); | ||
| 147 | if (buf == orgbuf) | ||
| 148 | buf += sprintf(buf, "other "); | ||
| 149 | |||
| 150 | buf += sprintf(buf - 1, "\n"); | ||
| 151 | |||
| 152 | return buf - orgbuf; | ||
| 153 | } | ||
| 154 | |||
| 155 | #define ADD_HOTPLUG_VAR(fmt, val...) \ | 202 | #define ADD_HOTPLUG_VAR(fmt, val...) \ |
| 156 | do { \ | 203 | do { \ |
| 157 | int err = add_uevent_var(env, fmt, val); \ | 204 | int err = add_uevent_var(env, fmt, val); \ |
| @@ -159,7 +206,7 @@ static ssize_t show_supported_protocols(struct device *d, | |||
| 159 | return err; \ | 206 | return err; \ |
| 160 | } while (0) | 207 | } while (0) |
| 161 | 208 | ||
| 162 | static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env) | 209 | static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) |
| 163 | { | 210 | { |
| 164 | struct ir_input_dev *ir_dev = dev_get_drvdata(device); | 211 | struct ir_input_dev *ir_dev = dev_get_drvdata(device); |
| 165 | 212 | ||
| @@ -174,34 +221,26 @@ static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env) | |||
| 174 | /* | 221 | /* |
| 175 | * Static device attribute struct with the sysfs attributes for IR's | 222 | * Static device attribute struct with the sysfs attributes for IR's |
| 176 | */ | 223 | */ |
| 177 | static DEVICE_ATTR(protocol, S_IRUGO | S_IWUSR, | 224 | static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR, |
| 178 | show_protocol, store_protocol); | 225 | show_protocols, store_protocols); |
| 179 | 226 | ||
| 180 | static DEVICE_ATTR(supported_protocols, S_IRUGO | S_IWUSR, | 227 | static struct attribute *rc_dev_attrs[] = { |
| 181 | show_supported_protocols, NULL); | 228 | &dev_attr_protocols.attr, |
| 182 | |||
| 183 | static struct attribute *ir_hw_dev_attrs[] = { | ||
| 184 | &dev_attr_protocol.attr, | ||
| 185 | &dev_attr_supported_protocols.attr, | ||
| 186 | NULL, | 229 | NULL, |
| 187 | }; | 230 | }; |
| 188 | 231 | ||
| 189 | static struct attribute_group ir_hw_dev_attr_grp = { | 232 | static struct attribute_group rc_dev_attr_grp = { |
| 190 | .attrs = ir_hw_dev_attrs, | 233 | .attrs = rc_dev_attrs, |
| 191 | }; | 234 | }; |
| 192 | 235 | ||
| 193 | static const struct attribute_group *ir_hw_dev_attr_groups[] = { | 236 | static const struct attribute_group *rc_dev_attr_groups[] = { |
| 194 | &ir_hw_dev_attr_grp, | 237 | &rc_dev_attr_grp, |
| 195 | NULL | 238 | NULL |
| 196 | }; | 239 | }; |
| 197 | 240 | ||
| 198 | static struct device_type rc_dev_type = { | 241 | static struct device_type rc_dev_type = { |
| 199 | .groups = ir_hw_dev_attr_groups, | 242 | .groups = rc_dev_attr_groups, |
| 200 | .uevent = ir_dev_uevent, | 243 | .uevent = rc_dev_uevent, |
| 201 | }; | ||
| 202 | |||
| 203 | static struct device_type ir_raw_dev_type = { | ||
| 204 | .uevent = ir_dev_uevent, | ||
| 205 | }; | 244 | }; |
| 206 | 245 | ||
| 207 | /** | 246 | /** |
| @@ -221,11 +260,7 @@ int ir_register_class(struct input_dev *input_dev) | |||
| 221 | if (unlikely(devno < 0)) | 260 | if (unlikely(devno < 0)) |
| 222 | return devno; | 261 | return devno; |
| 223 | 262 | ||
| 224 | if (ir_dev->props) { | 263 | ir_dev->dev.type = &rc_dev_type; |
| 225 | if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) | ||
| 226 | ir_dev->dev.type = &rc_dev_type; | ||
| 227 | } else | ||
| 228 | ir_dev->dev.type = &ir_raw_dev_type; | ||
| 229 | 264 | ||
| 230 | ir_dev->dev.class = &ir_input_class; | 265 | ir_dev->dev.class = &ir_input_class; |
| 231 | ir_dev->dev.parent = input_dev->dev.parent; | 266 | ir_dev->dev.parent = input_dev->dev.parent; |
