Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] media: rc: nuvoton: switch attribute wakeup_data to text

Switch attribute wakeup_data from binary to a text attribute.
This makes it easier to handle in userspace and allows to
use the output of tools like mode2 almost as is to set a
wakeup sequence.
Changing to a text format and values in microseconds also
makes the userspace interface independent of the setting of
SAMPLE_PERIOD in the driver.

In addition document the new sysfs attribute in
Documentation/ABI/testing/sysfs-class-rc-nuvoton.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>

authored by

Heiner Kallweit and committed by
Mauro Carvalho Chehab
02212001 fcbafafb

+68 -32
+15
Documentation/ABI/testing/sysfs-class-rc-nuvoton
··· 1 + What: /sys/class/rc/rcN/wakeup_data 2 + Date: Mar 2016 3 + KernelVersion: 4.6 4 + Contact: Mauro Carvalho Chehab <m.chehab@samsung.com> 5 + Description: 6 + Reading this file returns the stored CIR wakeup sequence. 7 + It starts with a pulse, followed by a space, pulse etc. 8 + All values are in microseconds. 9 + The same format can be used to store a wakeup sequence 10 + in the Nuvoton chip by writing to this file. 11 + 12 + Note: Some systems reset the stored wakeup sequence to a 13 + factory default on each boot. On such systems store the 14 + wakeup sequence in a file and set it on boot using e.g. 15 + a udev rule.
+53 -32
drivers/media/rc/nuvoton-cir.c
··· 179 179 } 180 180 } 181 181 182 - static ssize_t wakeup_data_read(struct file *fp, struct kobject *kobj, 183 - struct bin_attribute *bin_attr, 184 - char *buf, loff_t off, size_t count) 182 + static ssize_t wakeup_data_show(struct device *dev, 183 + struct device_attribute *attr, 184 + char *buf) 185 185 { 186 - struct device *dev = kobj_to_dev(kobj); 187 186 struct rc_dev *rc_dev = to_rc_dev(dev); 188 187 struct nvt_dev *nvt = rc_dev->priv; 189 - int fifo_len, len; 188 + int fifo_len, duration; 190 189 unsigned long flags; 190 + ssize_t buf_len = 0; 191 191 int i; 192 192 193 193 spin_lock_irqsave(&nvt->nvt_lock, flags); 194 194 195 195 fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT); 196 - len = min(fifo_len, WAKEUP_MAX_SIZE); 197 - 198 - if (off >= len) { 199 - spin_unlock_irqrestore(&nvt->nvt_lock, flags); 200 - return 0; 201 - } 202 - 203 - if (len > count) 204 - len = count; 196 + fifo_len = min(fifo_len, WAKEUP_MAX_SIZE); 205 197 206 198 /* go to first element to be read */ 207 - while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX) != off) 199 + while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) 208 200 nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY); 209 201 210 - for (i = 0; i < len; i++) 211 - buf[i] = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY); 202 + for (i = 0; i < fifo_len; i++) { 203 + duration = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY); 204 + duration = (duration & BUF_LEN_MASK) * SAMPLE_PERIOD; 205 + buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len, 206 + "%d ", duration); 207 + } 208 + buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len, "\n"); 212 209 213 210 spin_unlock_irqrestore(&nvt->nvt_lock, flags); 214 211 215 - return len; 212 + return buf_len; 216 213 } 217 214 218 - static ssize_t wakeup_data_write(struct file *fp, struct kobject *kobj, 219 - struct bin_attribute *bin_attr, 220 - char *buf, loff_t off, size_t count) 215 + static ssize_t wakeup_data_store(struct device *dev, 216 + struct device_attribute *attr, 217 + const char *buf, size_t len) 221 218 { 222 - struct device *dev = kobj_to_dev(kobj); 223 219 struct rc_dev *rc_dev = to_rc_dev(dev); 224 220 struct nvt_dev *nvt = rc_dev->priv; 225 221 unsigned long flags; 226 - u8 tolerance, config; 227 - int i; 222 + u8 tolerance, config, wake_buf[WAKEUP_MAX_SIZE]; 223 + char **argv; 224 + int i, count; 225 + unsigned int val; 226 + ssize_t ret; 228 227 229 - if (off > 0) 230 - return -EINVAL; 228 + argv = argv_split(GFP_KERNEL, buf, &count); 229 + if (!argv) 230 + return -ENOMEM; 231 + if (!count || count > WAKEUP_MAX_SIZE) { 232 + ret = -EINVAL; 233 + goto out; 234 + } 235 + 236 + for (i = 0; i < count; i++) { 237 + ret = kstrtouint(argv[i], 10, &val); 238 + if (ret) 239 + goto out; 240 + val = DIV_ROUND_CLOSEST(val, SAMPLE_PERIOD); 241 + if (!val || val > 0x7f) { 242 + ret = -EINVAL; 243 + goto out; 244 + } 245 + wake_buf[i] = val; 246 + /* sequence must start with a pulse */ 247 + if (i % 2 == 0) 248 + wake_buf[i] |= BUF_PULSE_BIT; 249 + } 231 250 232 251 /* hardcode the tolerance to 10% */ 233 252 tolerance = DIV_ROUND_UP(count, 10); ··· 264 245 CIR_WAKE_IRCON); 265 246 266 247 for (i = 0; i < count; i++) 267 - nvt_cir_wake_reg_write(nvt, buf[i], CIR_WAKE_WR_FIFO_DATA); 248 + nvt_cir_wake_reg_write(nvt, wake_buf[i], CIR_WAKE_WR_FIFO_DATA); 268 249 269 250 nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON); 270 251 271 252 spin_unlock_irqrestore(&nvt->nvt_lock, flags); 272 253 273 - return count; 254 + ret = len; 255 + out: 256 + argv_free(argv); 257 + return ret; 274 258 } 275 - 276 - static BIN_ATTR_RW(wakeup_data, WAKEUP_MAX_SIZE); 259 + static DEVICE_ATTR_RW(wakeup_data); 277 260 278 261 /* dump current cir register contents */ 279 262 static void cir_dump_regs(struct nvt_dev *nvt) ··· 1233 1212 NVT_DRIVER_NAME "-wake", (void *)nvt)) 1234 1213 goto exit_unregister_device; 1235 1214 1236 - ret = device_create_bin_file(&rdev->dev, &bin_attr_wakeup_data); 1215 + ret = device_create_file(&rdev->dev, &dev_attr_wakeup_data); 1237 1216 if (ret) 1238 1217 goto exit_unregister_device; 1239 1218 ··· 1260 1239 { 1261 1240 struct nvt_dev *nvt = pnp_get_drvdata(pdev); 1262 1241 1263 - device_remove_bin_file(&nvt->rdev->dev, &bin_attr_wakeup_data); 1242 + device_remove_file(&nvt->rdev->dev, &dev_attr_wakeup_data); 1264 1243 1265 1244 nvt_disable_cir(nvt); 1266 1245