From 4e3cd001fde13dfd4a91888f908b2a07fd0a4047 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 8 Jun 2017 05:10:41 -0400 Subject: media: lirc: remove LIRCCODE and LIRC_GET_LENGTH LIRCCODE is a lirc mode where a driver produces driver-dependent codes for receive and transmit. No driver uses this any more. The LIRC_GET_LENGTH ioctl was used for this mode only. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 4fd4521693d9..9954ad4b8e59 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -388,7 +388,6 @@ static int ir_lirc_register(struct rc_dev *dev) ldev->features = features; ldev->data = &dev->raw->lirc; ldev->buf = NULL; - ldev->code_length = sizeof(struct ir_raw_event) * 8; ldev->chunk_size = sizeof(int); ldev->buffer_size = LIRCBUF_SIZE; ldev->fops = &lirc_fops; -- cgit From 9b6192589be788dec73a0e99fe49b8f8ddaf825e Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 25 Feb 2017 06:51:29 -0500 Subject: media: lirc: implement scancode sending This introduces a new lirc mode: scancode. Any device which can send raw IR can now also send scancodes. int main() { int mode, fd = open("/dev/lirc0", O_RDWR); mode = LIRC_MODE_SCANCODE; if (ioctl(fd, LIRC_SET_SEND_MODE, &mode)) { // kernel too old or lirc does not support transmit } struct lirc_scancode scancode = { .scancode = 0x1e3d, .rc_proto = RC_PROTO_RC5, }; write(fd, &scancode, sizeof(scancode)); close(fd); } The other fields of lirc_scancode must be set to 0. Note that toggle (rc5, rc6) and repeats (nec) are not implemented. Nor is there a method for holding down a key for a period. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 99 +++++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 27 deletions(-) (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 9954ad4b8e59..0a3ec693d290 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -107,7 +107,8 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, { struct lirc_codec *lirc; struct rc_dev *dev; - unsigned int *txbuf; /* buffer with values to transmit */ + unsigned int *txbuf = NULL; + struct ir_raw_event *raw = NULL; ssize_t ret = -EINVAL; size_t count; ktime_t start; @@ -121,16 +122,50 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, if (!lirc) return -EFAULT; - if (n < sizeof(unsigned) || n % sizeof(unsigned)) - return -EINVAL; + if (lirc->send_mode == LIRC_MODE_SCANCODE) { + struct lirc_scancode scan; - count = n / sizeof(unsigned); - if (count > LIRCBUF_SIZE || count % 2 == 0) - return -EINVAL; + if (n != sizeof(scan)) + return -EINVAL; - txbuf = memdup_user(buf, n); - if (IS_ERR(txbuf)) - return PTR_ERR(txbuf); + if (copy_from_user(&scan, buf, sizeof(scan))) + return -EFAULT; + + if (scan.flags || scan.keycode || scan.timestamp) + return -EINVAL; + + raw = kmalloc_array(LIRCBUF_SIZE, sizeof(*raw), GFP_KERNEL); + if (!raw) + return -ENOMEM; + + ret = ir_raw_encode_scancode(scan.rc_proto, scan.scancode, + raw, LIRCBUF_SIZE); + if (ret < 0) + goto out; + + count = ret; + + txbuf = kmalloc_array(count, sizeof(unsigned int), GFP_KERNEL); + if (!txbuf) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < count; i++) + /* Convert from NS to US */ + txbuf[i] = DIV_ROUND_UP(raw[i].duration, 1000); + } else { + if (n < sizeof(unsigned int) || n % sizeof(unsigned int)) + return -EINVAL; + + count = n / sizeof(unsigned int); + if (count > LIRCBUF_SIZE || count % 2 == 0) + return -EINVAL; + + txbuf = memdup_user(buf, n); + if (IS_ERR(txbuf)) + return PTR_ERR(txbuf); + } dev = lirc->dev; if (!dev) { @@ -156,24 +191,30 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, if (ret < 0) goto out; - for (duration = i = 0; i < ret; i++) - duration += txbuf[i]; - - ret *= sizeof(unsigned int); - - /* - * The lircd gap calculation expects the write function to - * wait for the actual IR signal to be transmitted before - * returning. - */ - towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get()); - if (towait > 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(usecs_to_jiffies(towait)); + if (lirc->send_mode == LIRC_MODE_SCANCODE) { + ret = n; + } else { + for (duration = i = 0; i < ret; i++) + duration += txbuf[i]; + + ret *= sizeof(unsigned int); + + /* + * The lircd gap calculation expects the write function to + * wait for the actual IR signal to be transmitted before + * returning. + */ + towait = ktime_us_delta(ktime_add_us(start, duration), + ktime_get()); + if (towait > 0) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(usecs_to_jiffies(towait)); + } } out: kfree(txbuf); + kfree(raw); return ret; } @@ -202,20 +243,22 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, switch (cmd) { - /* legacy support */ + /* mode support */ case LIRC_GET_SEND_MODE: if (!dev->tx_ir) return -ENOTTY; - val = LIRC_MODE_PULSE; + val = lirc->send_mode; break; case LIRC_SET_SEND_MODE: if (!dev->tx_ir) return -ENOTTY; - if (val != LIRC_MODE_PULSE) + if (!(val == LIRC_MODE_PULSE || val == LIRC_MODE_SCANCODE)) return -EINVAL; + + lirc->send_mode = val; return 0; /* TX settings */ @@ -361,7 +404,7 @@ static int ir_lirc_register(struct rc_dev *dev) } if (dev->tx_ir) { - features |= LIRC_CAN_SEND_PULSE; + features |= LIRC_CAN_SEND_PULSE | LIRC_CAN_SEND_SCANCODE; if (dev->s_tx_mask) features |= LIRC_CAN_SET_TRANSMITTER_MASK; if (dev->s_tx_carrier) @@ -399,6 +442,8 @@ static int ir_lirc_register(struct rc_dev *dev) if (rc < 0) goto out; + dev->raw->lirc.send_mode = LIRC_MODE_PULSE; + dev->raw->lirc.ldev = ldev; dev->raw->lirc.dev = dev; return 0; -- cgit From cdfaa01c1cfeb828e6d3c0c5e4f54375fc3ccb95 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 25 Feb 2017 06:51:30 -0500 Subject: media: lirc: use the correct carrier for scancode transmit If the lirc device supports it, set the carrier for the protocol. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 0a3ec693d290..bdacbadac416 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -122,6 +122,17 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, if (!lirc) return -EFAULT; + dev = lirc->dev; + if (!dev) { + ret = -EFAULT; + goto out; + } + + if (!dev->tx_ir) { + ret = -EINVAL; + goto out; + } + if (lirc->send_mode == LIRC_MODE_SCANCODE) { struct lirc_scancode scan; @@ -154,6 +165,13 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, for (i = 0; i < count; i++) /* Convert from NS to US */ txbuf[i] = DIV_ROUND_UP(raw[i].duration, 1000); + + if (dev->s_tx_carrier) { + int carrier = ir_raw_encode_carrier(scan.rc_proto); + + if (carrier > 0) + dev->s_tx_carrier(dev, carrier); + } } else { if (n < sizeof(unsigned int) || n % sizeof(unsigned int)) return -EINVAL; @@ -167,17 +185,6 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, return PTR_ERR(txbuf); } - dev = lirc->dev; - if (!dev) { - ret = -EFAULT; - goto out; - } - - if (!dev->tx_ir) { - ret = -EINVAL; - goto out; - } - for (i = 0; i < count; i++) { if (txbuf[i] > IR_MAX_DURATION / 1000 - duration || !txbuf[i]) { ret = -EINVAL; -- cgit From a60d64b15c20d178ba3a9bc3a542492b4ddeea70 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 23 Sep 2017 10:41:13 -0400 Subject: media: lirc: lirc interface should not be a raw decoder The lirc user interface exists as a raw decoder, which does not make much sense for transmit-only devices. In addition, we want to have lirc char devices for devices which do not use raw IR, i.e. scancode only devices. Note that rc-code, lirc_dev, ir-lirc-codec are now calling functions of each other, so they've been merged into one module rc-core to avoid circular dependencies. Since ir-lirc-codec no longer exists as separate codec module, there is no need for RC_DRIVER_IR_RAW_TX type drivers to call ir_raw_event_register(). Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 135 +++++++++++---------------------------- 1 file changed, 36 insertions(+), 99 deletions(-) (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index bdacbadac416..aec0109b1a69 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -23,21 +22,15 @@ #define LIRCBUF_SIZE 256 /** - * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the - * lircd userspace daemon for decoding. + * ir_lirc_raw_event() - Send raw IR data to lirc to be relayed to userspace + * * @dev: the struct rc_dev descriptor of the device * @ev: the struct ir_raw_event descriptor of the pulse/space - * - * This function returns -EINVAL if the lirc interfaces aren't wired up. */ -static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) +void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) { - struct lirc_codec *lirc = &dev->raw->lirc; int sample; - if (!dev->raw->lirc.ldev || !dev->raw->lirc.ldev->buf) - return -EINVAL; - /* Packet start */ if (ev.reset) { /* Userspace expects a long space event before the start of @@ -56,15 +49,15 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) /* Packet end */ } else if (ev.timeout) { - if (lirc->gap) - return 0; + if (dev->gap) + return; - lirc->gap_start = ktime_get(); - lirc->gap = true; - lirc->gap_duration = ev.duration; + dev->gap_start = ktime_get(); + dev->gap = true; + dev->gap_duration = ev.duration; - if (!lirc->send_timeout_reports) - return 0; + if (!dev->send_timeout_reports) + return; sample = LIRC_TIMEOUT(ev.duration / 1000); IR_dprintk(2, "timeout report (duration: %d)\n", sample); @@ -72,21 +65,21 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) /* Normal sample */ } else { - if (lirc->gap) { + if (dev->gap) { int gap_sample; - lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(), - lirc->gap_start)); + dev->gap_duration += ktime_to_ns(ktime_sub(ktime_get(), + dev->gap_start)); /* Convert to ms and cap by LIRC_VALUE_MASK */ - do_div(lirc->gap_duration, 1000); - lirc->gap_duration = min(lirc->gap_duration, - (u64)LIRC_VALUE_MASK); + do_div(dev->gap_duration, 1000); + dev->gap_duration = min_t(u64, dev->gap_duration, + LIRC_VALUE_MASK); - gap_sample = LIRC_SPACE(lirc->gap_duration); - lirc_buffer_write(dev->raw->lirc.ldev->buf, + gap_sample = LIRC_SPACE(dev->gap_duration); + lirc_buffer_write(dev->lirc_dev->buf, (unsigned char *)&gap_sample); - lirc->gap = false; + dev->gap = false; } sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) : @@ -95,18 +88,16 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) TO_US(ev.duration), TO_STR(ev.pulse)); } - lirc_buffer_write(dev->raw->lirc.ldev->buf, + lirc_buffer_write(dev->lirc_dev->buf, (unsigned char *) &sample); - wake_up(&dev->raw->lirc.ldev->buf->wait_poll); - return 0; + wake_up(&dev->lirc_dev->buf->wait_poll); } static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, size_t n, loff_t *ppos) { - struct lirc_codec *lirc; - struct rc_dev *dev; + struct rc_dev *dev = file->private_data; unsigned int *txbuf = NULL; struct ir_raw_event *raw = NULL; ssize_t ret = -EINVAL; @@ -118,22 +109,12 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, start = ktime_get(); - lirc = lirc_get_pdata(file); - if (!lirc) - return -EFAULT; - - dev = lirc->dev; - if (!dev) { - ret = -EFAULT; - goto out; - } - if (!dev->tx_ir) { ret = -EINVAL; goto out; } - if (lirc->send_mode == LIRC_MODE_SCANCODE) { + if (dev->send_mode == LIRC_MODE_SCANCODE) { struct lirc_scancode scan; if (n != sizeof(scan)) @@ -198,7 +179,7 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, if (ret < 0) goto out; - if (lirc->send_mode == LIRC_MODE_SCANCODE) { + if (dev->send_mode == LIRC_MODE_SCANCODE) { ret = n; } else { for (duration = i = 0; i < ret; i++) @@ -228,20 +209,11 @@ out: static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { - struct lirc_codec *lirc; - struct rc_dev *dev; + struct rc_dev *dev = filep->private_data; u32 __user *argp = (u32 __user *)(arg); int ret = 0; __u32 val = 0, tmp; - lirc = lirc_get_pdata(filep); - if (!lirc) - return -EFAULT; - - dev = lirc->dev; - if (!dev) - return -EFAULT; - if (_IOC_DIR(cmd) & _IOC_WRITE) { ret = get_user(val, argp); if (ret) @@ -255,7 +227,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, if (!dev->tx_ir) return -ENOTTY; - val = lirc->send_mode; + val = dev->send_mode; break; case LIRC_SET_SEND_MODE: @@ -265,7 +237,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, if (!(val == LIRC_MODE_PULSE || val == LIRC_MODE_SCANCODE)) return -EINVAL; - lirc->send_mode = val; + dev->send_mode = val; return 0; /* TX settings */ @@ -299,7 +271,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, return -EINVAL; return dev->s_rx_carrier_range(dev, - dev->raw->lirc.carrier_low, + dev->carrier_low, val); case LIRC_SET_REC_CARRIER_RANGE: @@ -309,7 +281,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, if (val <= 0) return -EINVAL; - dev->raw->lirc.carrier_low = val; + dev->carrier_low = val; return 0; case LIRC_GET_REC_RESOLUTION: @@ -367,7 +339,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, if (!dev->timeout) return -ENOTTY; - lirc->send_timeout_reports = !!val; + dev->send_timeout_reports = !!val; break; default: @@ -394,7 +366,7 @@ static const struct file_operations lirc_fops = { .llseek = no_llseek, }; -static int ir_lirc_register(struct rc_dev *dev) +int ir_lirc_register(struct rc_dev *dev) { struct lirc_dev *ldev; int rc = -ENOMEM; @@ -436,7 +408,6 @@ static int ir_lirc_register(struct rc_dev *dev) snprintf(ldev->name, sizeof(ldev->name), "ir-lirc-codec (%s)", dev->driver_name); ldev->features = features; - ldev->data = &dev->raw->lirc; ldev->buf = NULL; ldev->chunk_size = sizeof(int); ldev->buffer_size = LIRCBUF_SIZE; @@ -449,10 +420,8 @@ static int ir_lirc_register(struct rc_dev *dev) if (rc < 0) goto out; - dev->raw->lirc.send_mode = LIRC_MODE_PULSE; - - dev->raw->lirc.ldev = ldev; - dev->raw->lirc.dev = dev; + dev->send_mode = LIRC_MODE_PULSE; + dev->lirc_dev = ldev; return 0; out: @@ -460,40 +429,8 @@ out: return rc; } -static int ir_lirc_unregister(struct rc_dev *dev) -{ - struct lirc_codec *lirc = &dev->raw->lirc; - - lirc_unregister_device(lirc->ldev); - lirc->ldev = NULL; - - return 0; -} - -static struct ir_raw_handler lirc_handler = { - .protocols = 0, - .decode = ir_lirc_decode, - .raw_register = ir_lirc_register, - .raw_unregister = ir_lirc_unregister, -}; - -static int __init ir_lirc_codec_init(void) +void ir_lirc_unregister(struct rc_dev *dev) { - ir_raw_handler_register(&lirc_handler); - - printk(KERN_INFO "IR LIRC bridge handler initialized\n"); - return 0; -} - -static void __exit ir_lirc_codec_exit(void) -{ - ir_raw_handler_unregister(&lirc_handler); + lirc_unregister_device(dev->lirc_dev); + dev->lirc_dev = NULL; } - -module_init(ir_lirc_codec_init); -module_exit(ir_lirc_codec_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jarod Wilson "); -MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); -MODULE_DESCRIPTION("LIRC IR handler bridge"); -- cgit From 49a4b36ada336270b564cabbbcb727cadebd024d Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 27 Sep 2017 16:00:49 -0400 Subject: media: lirc: validate scancode for transmit Ensure we reject an attempt to transmit invalid scancodes. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index aec0109b1a69..1ed69c9e64bf 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -126,6 +126,16 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, if (scan.flags || scan.keycode || scan.timestamp) return -EINVAL; + /* + * The scancode field in lirc_scancode is 64-bit simply + * to future-proof it, since there are IR protocols encode + * use more than 32 bits. For now only 32-bit protocols + * are supported. + */ + if (scan.scancode > U32_MAX || + !rc_validate_scancode(scan.rc_proto, scan.scancode)) + return -EINVAL; + raw = kmalloc_array(LIRCBUF_SIZE, sizeof(*raw), GFP_KERNEL); if (!raw) return -ENOMEM; -- cgit From 95bc71e199e50487054adfd8222c5105deddbbd9 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 23 Sep 2017 12:05:59 -0400 Subject: media: lirc: merge lirc_dev_fop_ioctl and ir_lirc_ioctl Calculate lirc features when necessary, and add LIRC_{S,G}ET_REC_MODE cases to ir_lirc_ioctl. This makes lirc_dev_fop_ioctl() unnecessary since all cases are already handled by ir_lirc_ioctl(). Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 79 ++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 32 deletions(-) (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 1ed69c9e64bf..f933e7617882 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -231,8 +231,54 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, } switch (cmd) { + case LIRC_GET_FEATURES: + if (dev->driver_type == RC_DRIVER_IR_RAW) { + val |= LIRC_CAN_REC_MODE2; + if (dev->rx_resolution) + val |= LIRC_CAN_GET_REC_RESOLUTION; + } + + if (dev->tx_ir) { + val |= LIRC_CAN_SEND_PULSE | LIRC_CAN_SEND_SCANCODE; + if (dev->s_tx_mask) + val |= LIRC_CAN_SET_TRANSMITTER_MASK; + if (dev->s_tx_carrier) + val |= LIRC_CAN_SET_SEND_CARRIER; + if (dev->s_tx_duty_cycle) + val |= LIRC_CAN_SET_SEND_DUTY_CYCLE; + } + + if (dev->s_rx_carrier_range) + val |= LIRC_CAN_SET_REC_CARRIER | + LIRC_CAN_SET_REC_CARRIER_RANGE; + + if (dev->s_learning_mode) + val |= LIRC_CAN_USE_WIDEBAND_RECEIVER; + + if (dev->s_carrier_report) + val |= LIRC_CAN_MEASURE_CARRIER; + + if (dev->max_timeout) + val |= LIRC_CAN_SET_REC_TIMEOUT; + + break; /* mode support */ + case LIRC_GET_REC_MODE: + if (dev->driver_type == RC_DRIVER_IR_RAW_TX) + return -ENOTTY; + + val = LIRC_MODE_MODE2; + break; + + case LIRC_SET_REC_MODE: + if (dev->driver_type == RC_DRIVER_IR_RAW_TX) + return -ENOTTY; + + if (val != LIRC_MODE_MODE2) + return -EINVAL; + return 0; + case LIRC_GET_SEND_MODE: if (!dev->tx_ir) return -ENOTTY; @@ -353,7 +399,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, break; default: - return lirc_dev_fop_ioctl(filep, cmd, arg); + return -ENOTTY; } if (_IOC_DIR(cmd) & _IOC_READ) @@ -380,44 +426,13 @@ int ir_lirc_register(struct rc_dev *dev) { struct lirc_dev *ldev; int rc = -ENOMEM; - unsigned long features = 0; ldev = lirc_allocate_device(); if (!ldev) return rc; - if (dev->driver_type != RC_DRIVER_IR_RAW_TX) { - features |= LIRC_CAN_REC_MODE2; - if (dev->rx_resolution) - features |= LIRC_CAN_GET_REC_RESOLUTION; - } - - if (dev->tx_ir) { - features |= LIRC_CAN_SEND_PULSE | LIRC_CAN_SEND_SCANCODE; - if (dev->s_tx_mask) - features |= LIRC_CAN_SET_TRANSMITTER_MASK; - if (dev->s_tx_carrier) - features |= LIRC_CAN_SET_SEND_CARRIER; - if (dev->s_tx_duty_cycle) - features |= LIRC_CAN_SET_SEND_DUTY_CYCLE; - } - - if (dev->s_rx_carrier_range) - features |= LIRC_CAN_SET_REC_CARRIER | - LIRC_CAN_SET_REC_CARRIER_RANGE; - - if (dev->s_learning_mode) - features |= LIRC_CAN_USE_WIDEBAND_RECEIVER; - - if (dev->s_carrier_report) - features |= LIRC_CAN_MEASURE_CARRIER; - - if (dev->max_timeout) - features |= LIRC_CAN_SET_REC_TIMEOUT; - snprintf(ldev->name, sizeof(ldev->name), "ir-lirc-codec (%s)", dev->driver_name); - ldev->features = features; ldev->buf = NULL; ldev->chunk_size = sizeof(int); ldev->buffer_size = LIRCBUF_SIZE; -- cgit From 71695aff9fe036857596965635e2607cf561a230 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 23 Sep 2017 14:44:18 -0400 Subject: media: lirc: use kfifo rather than lirc_buffer for raw IR Since the only mode lirc devices can handle is raw IR, handle this in a plain kfifo. Remove lirc_buffer since this is no longer needed. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 81 +++++++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 14 deletions(-) (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index f933e7617882..2fa1f905a266 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -66,8 +66,6 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) } else { if (dev->gap) { - int gap_sample; - dev->gap_duration += ktime_to_ns(ktime_sub(ktime_get(), dev->gap_start)); @@ -76,9 +74,7 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) dev->gap_duration = min_t(u64, dev->gap_duration, LIRC_VALUE_MASK); - gap_sample = LIRC_SPACE(dev->gap_duration); - lirc_buffer_write(dev->lirc_dev->buf, - (unsigned char *)&gap_sample); + kfifo_put(&dev->rawir, LIRC_SPACE(dev->gap_duration)); dev->gap = false; } @@ -88,10 +84,8 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) TO_US(ev.duration), TO_STR(ev.pulse)); } - lirc_buffer_write(dev->lirc_dev->buf, - (unsigned char *) &sample); - - wake_up(&dev->lirc_dev->buf->wait_poll); + kfifo_put(&dev->rawir, sample); + wake_up_poll(&dev->wait_poll, POLLIN | POLLRDNORM); } static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, @@ -408,6 +402,68 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, return ret; } +static unsigned int ir_lirc_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct rc_dev *rcdev = file->private_data; + struct lirc_dev *d = rcdev->lirc_dev; + unsigned int events = 0; + + poll_wait(file, &rcdev->wait_poll, wait); + + if (!d->attached) + events = POLLHUP | POLLERR; + else if (rcdev->driver_type == RC_DRIVER_IR_RAW && + !kfifo_is_empty(&rcdev->rawir)) + events = POLLIN | POLLRDNORM; + + return events; +} + +static ssize_t ir_lirc_read(struct file *file, char __user *buffer, + size_t length, loff_t *ppos) +{ + struct rc_dev *rcdev = file->private_data; + struct lirc_dev *d = rcdev->lirc_dev; + unsigned int copied; + int ret; + + if (rcdev->driver_type == RC_DRIVER_IR_RAW_TX) + return -EINVAL; + + if (length < sizeof(unsigned int) || length % sizeof(unsigned int)) + return -EINVAL; + + if (!d->attached) + return -ENODEV; + + do { + if (kfifo_is_empty(&rcdev->rawir)) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible(rcdev->wait_poll, + !kfifo_is_empty(&rcdev->rawir) || + !d->attached); + if (ret) + return ret; + } + + if (!d->attached) + return -ENODEV; + + ret = mutex_lock_interruptible(&rcdev->lock); + if (ret) + return ret; + ret = kfifo_to_user(&rcdev->rawir, buffer, length, &copied); + mutex_unlock(&rcdev->lock); + if (ret) + return ret; + } while (copied == 0); + + return copied; +} + static const struct file_operations lirc_fops = { .owner = THIS_MODULE, .write = ir_lirc_transmit_ir, @@ -415,8 +471,8 @@ static const struct file_operations lirc_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = ir_lirc_ioctl, #endif - .read = lirc_dev_fop_read, - .poll = lirc_dev_fop_poll, + .read = ir_lirc_read, + .poll = ir_lirc_poll, .open = lirc_dev_fop_open, .release = lirc_dev_fop_close, .llseek = no_llseek, @@ -433,9 +489,6 @@ int ir_lirc_register(struct rc_dev *dev) snprintf(ldev->name, sizeof(ldev->name), "ir-lirc-codec (%s)", dev->driver_name); - ldev->buf = NULL; - ldev->chunk_size = sizeof(int); - ldev->buffer_size = LIRCBUF_SIZE; ldev->fops = &lirc_fops; ldev->dev.parent = &dev->dev; ldev->rdev = dev; -- cgit From 7790e81f7e1f7f122f8fcccd91443a2571421aba Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 26 Sep 2017 07:31:29 -0400 Subject: media: lirc: move lirc_dev->attached to rc_dev->registered This is done to further remove the lirc kernel api. Ensure that every fops checks for this. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 2fa1f905a266..ff74a5d7a0f3 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -101,6 +101,9 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, unsigned int duration = 0; /* signal duration in us */ int i; + if (!dev->registered) + return -ENODEV; + start = ktime_get(); if (!dev->tx_ir) { @@ -224,6 +227,9 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, return ret; } + if (!dev->registered) + return -ENODEV; + switch (cmd) { case LIRC_GET_FEATURES: if (dev->driver_type == RC_DRIVER_IR_RAW) { @@ -406,12 +412,11 @@ static unsigned int ir_lirc_poll(struct file *file, struct poll_table_struct *wait) { struct rc_dev *rcdev = file->private_data; - struct lirc_dev *d = rcdev->lirc_dev; unsigned int events = 0; poll_wait(file, &rcdev->wait_poll, wait); - if (!d->attached) + if (!rcdev->registered) events = POLLHUP | POLLERR; else if (rcdev->driver_type == RC_DRIVER_IR_RAW && !kfifo_is_empty(&rcdev->rawir)) @@ -424,7 +429,6 @@ static ssize_t ir_lirc_read(struct file *file, char __user *buffer, size_t length, loff_t *ppos) { struct rc_dev *rcdev = file->private_data; - struct lirc_dev *d = rcdev->lirc_dev; unsigned int copied; int ret; @@ -434,7 +438,7 @@ static ssize_t ir_lirc_read(struct file *file, char __user *buffer, if (length < sizeof(unsigned int) || length % sizeof(unsigned int)) return -EINVAL; - if (!d->attached) + if (!rcdev->registered) return -ENODEV; do { @@ -444,12 +448,12 @@ static ssize_t ir_lirc_read(struct file *file, char __user *buffer, ret = wait_event_interruptible(rcdev->wait_poll, !kfifo_is_empty(&rcdev->rawir) || - !d->attached); + !rcdev->registered); if (ret) return ret; } - if (!d->attached) + if (!rcdev->registered) return -ENODEV; ret = mutex_lock_interruptible(&rcdev->lock); -- cgit From 111429fb73b1f5f584d977614b87ce9e6f8361c6 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 26 Sep 2017 07:44:20 -0400 Subject: media: lirc: create rc-core open and close lirc functions Replace the generic kernel lirc api with ones which use rc-core, further reducing the lirc_dev members. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 59 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index ff74a5d7a0f3..1e921e4f8839 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -88,6 +88,61 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) wake_up_poll(&dev->wait_poll, POLLIN | POLLRDNORM); } +static int ir_lirc_open(struct inode *inode, struct file *file) +{ + struct lirc_dev *d = container_of(inode->i_cdev, struct lirc_dev, cdev); + struct rc_dev *dev = d->rdev; + int retval; + + retval = rc_open(dev); + if (retval) + return retval; + + retval = mutex_lock_interruptible(&dev->lock); + if (retval) + goto out_rc; + + if (!dev->registered) { + retval = -ENODEV; + goto out_unlock; + } + + if (dev->lirc_open) { + retval = -EBUSY; + goto out_unlock; + } + + if (dev->driver_type == RC_DRIVER_IR_RAW) + kfifo_reset_out(&dev->rawir); + + dev->lirc_open++; + file->private_data = dev; + + nonseekable_open(inode, file); + mutex_unlock(&dev->lock); + + return 0; + +out_unlock: + mutex_unlock(&dev->lock); +out_rc: + rc_close(dev); + return retval; +} + +static int ir_lirc_close(struct inode *inode, struct file *file) +{ + struct rc_dev *dev = file->private_data; + + mutex_lock(&dev->lock); + dev->lirc_open--; + mutex_unlock(&dev->lock); + + rc_close(dev); + + return 0; +} + static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, size_t n, loff_t *ppos) { @@ -477,8 +532,8 @@ static const struct file_operations lirc_fops = { #endif .read = ir_lirc_read, .poll = ir_lirc_poll, - .open = lirc_dev_fop_open, - .release = lirc_dev_fop_close, + .open = ir_lirc_open, + .release = ir_lirc_close, .llseek = no_llseek, }; -- cgit From bf01c82474bf1f5c07d90a0959a95ff51374cc6f Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 26 Sep 2017 07:56:39 -0400 Subject: media: lirc: remove name from lirc_dev This is a duplicate of rcdev->driver_name. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 1e921e4f8839..6435306f385b 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -546,8 +546,6 @@ int ir_lirc_register(struct rc_dev *dev) if (!ldev) return rc; - snprintf(ldev->name, sizeof(ldev->name), "ir-lirc-codec (%s)", - dev->driver_name); ldev->fops = &lirc_fops; ldev->dev.parent = &dev->dev; ldev->rdev = dev; -- cgit From a6ddd4fecbb02d8ec5a865621bd2b746d585a01c Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 26 Sep 2017 09:34:47 -0400 Subject: media: lirc: remove last remnants of lirc kapi rc-core has replaced the lirc kapi many years ago, and now with the last driver ported to rc-core, we can finally remove it. Note this has no effect on userspace. All future IR drivers should use the rc-core api. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 41 ++++------------------------------------ 1 file changed, 4 insertions(+), 37 deletions(-) (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 6435306f385b..52daac9bc470 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -12,10 +12,10 @@ * GNU General Public License for more details. */ +#include #include #include #include -#include #include #include "rc-core-priv.h" @@ -90,8 +90,8 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) static int ir_lirc_open(struct inode *inode, struct file *file) { - struct lirc_dev *d = container_of(inode->i_cdev, struct lirc_dev, cdev); - struct rc_dev *dev = d->rdev; + struct rc_dev *dev = container_of(inode->i_cdev, struct rc_dev, + lirc_cdev); int retval; retval = rc_open(dev); @@ -523,7 +523,7 @@ static ssize_t ir_lirc_read(struct file *file, char __user *buffer, return copied; } -static const struct file_operations lirc_fops = { +const struct file_operations lirc_fops = { .owner = THIS_MODULE, .write = ir_lirc_transmit_ir, .unlocked_ioctl = ir_lirc_ioctl, @@ -536,36 +536,3 @@ static const struct file_operations lirc_fops = { .release = ir_lirc_close, .llseek = no_llseek, }; - -int ir_lirc_register(struct rc_dev *dev) -{ - struct lirc_dev *ldev; - int rc = -ENOMEM; - - ldev = lirc_allocate_device(); - if (!ldev) - return rc; - - ldev->fops = &lirc_fops; - ldev->dev.parent = &dev->dev; - ldev->rdev = dev; - ldev->owner = THIS_MODULE; - - rc = lirc_register_device(ldev); - if (rc < 0) - goto out; - - dev->send_mode = LIRC_MODE_PULSE; - dev->lirc_dev = ldev; - return 0; - -out: - lirc_free_device(ldev); - return rc; -} - -void ir_lirc_unregister(struct rc_dev *dev) -{ - lirc_unregister_device(dev->lirc_dev); - dev->lirc_dev = NULL; -} -- cgit From de142c32410649e64d44928505ffad2176a96a9e Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 25 Feb 2017 06:51:32 -0500 Subject: media: lirc: implement reading scancode This implements LIRC_MODE_SCANCODE reading from the lirc device. The scancode can be read from the input device too, but with this interface you get the rc protocol, keycode, toggle and repeat status in addition to just the scancode. int main() { int fd, mode, rc; fd = open("/dev/lirc0", O_RDWR); mode = LIRC_MODE_SCANCODE; if (ioctl(fd, LIRC_SET_REC_MODE, &mode)) { // kernel too old or lirc does not support transmit } struct lirc_scancode scancode; while (read(fd, &scancode, sizeof(scancode)) == sizeof(scancode)) { printf("protocol:%d scancode:0x%x toggle:%d repeat:%d\n", scancode.rc_proto, scancode.scancode, !!(scancode.flags & LIRC_SCANCODE_FLAG_TOGGLE), !!(scancode.flags & LIRC_SCANCODE_FLAG_REPEAT)); } close(fd); } Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 104 +++++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 15 deletions(-) (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 52daac9bc470..817258c87b5c 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -88,6 +88,21 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) wake_up_poll(&dev->wait_poll, POLLIN | POLLRDNORM); } +/** + * ir_lirc_scancode_event() - Send scancode data to lirc to be relayed to + * userspace + * @dev: the struct rc_dev descriptor of the device + * @lsc: the struct lirc_scancode describing the decoded scancode + */ +void ir_lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc) +{ + lsc->timestamp = ktime_get_ns(); + + if (kfifo_put(&dev->scancodes, *lsc)) + wake_up_poll(&dev->wait_poll, POLLIN | POLLRDNORM); +} +EXPORT_SYMBOL_GPL(ir_lirc_scancode_event); + static int ir_lirc_open(struct inode *inode, struct file *file) { struct rc_dev *dev = container_of(inode->i_cdev, struct rc_dev, @@ -114,6 +129,8 @@ static int ir_lirc_open(struct inode *inode, struct file *file) if (dev->driver_type == RC_DRIVER_IR_RAW) kfifo_reset_out(&dev->rawir); + if (dev->driver_type != RC_DRIVER_IR_RAW_TX) + kfifo_reset_out(&dev->scancodes); dev->lirc_open++; file->private_data = dev; @@ -288,7 +305,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, switch (cmd) { case LIRC_GET_FEATURES: if (dev->driver_type == RC_DRIVER_IR_RAW) { - val |= LIRC_CAN_REC_MODE2; + val |= LIRC_CAN_REC_MODE2 | LIRC_CAN_REC_SCANCODE; if (dev->rx_resolution) val |= LIRC_CAN_GET_REC_RESOLUTION; } @@ -323,15 +340,17 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, if (dev->driver_type == RC_DRIVER_IR_RAW_TX) return -ENOTTY; - val = LIRC_MODE_MODE2; + val = dev->rec_mode; break; case LIRC_SET_REC_MODE: if (dev->driver_type == RC_DRIVER_IR_RAW_TX) return -ENOTTY; - if (val != LIRC_MODE_MODE2) + if (!(val == LIRC_MODE_MODE2 || val == LIRC_MODE_SCANCODE)) return -EINVAL; + + dev->rec_mode = val; return 0; case LIRC_GET_SEND_MODE: @@ -471,31 +490,31 @@ static unsigned int ir_lirc_poll(struct file *file, poll_wait(file, &rcdev->wait_poll, wait); - if (!rcdev->registered) + if (!rcdev->registered) { events = POLLHUP | POLLERR; - else if (rcdev->driver_type == RC_DRIVER_IR_RAW && - !kfifo_is_empty(&rcdev->rawir)) - events = POLLIN | POLLRDNORM; + } else if (rcdev->driver_type != RC_DRIVER_IR_RAW_TX) { + if (rcdev->rec_mode == LIRC_MODE_SCANCODE && + !kfifo_is_empty(&rcdev->scancodes)) + events = POLLIN | POLLRDNORM; + + if (rcdev->rec_mode == LIRC_MODE_MODE2 && + !kfifo_is_empty(&rcdev->rawir)) + events = POLLIN | POLLRDNORM; + } return events; } -static ssize_t ir_lirc_read(struct file *file, char __user *buffer, - size_t length, loff_t *ppos) +static ssize_t ir_lirc_read_mode2(struct file *file, char __user *buffer, + size_t length) { struct rc_dev *rcdev = file->private_data; unsigned int copied; int ret; - if (rcdev->driver_type == RC_DRIVER_IR_RAW_TX) - return -EINVAL; - if (length < sizeof(unsigned int) || length % sizeof(unsigned int)) return -EINVAL; - if (!rcdev->registered) - return -ENODEV; - do { if (kfifo_is_empty(&rcdev->rawir)) { if (file->f_flags & O_NONBLOCK) @@ -523,6 +542,61 @@ static ssize_t ir_lirc_read(struct file *file, char __user *buffer, return copied; } +static ssize_t ir_lirc_read_scancode(struct file *file, char __user *buffer, + size_t length) +{ + struct rc_dev *rcdev = file->private_data; + unsigned int copied; + int ret; + + if (length < sizeof(struct lirc_scancode) || + length % sizeof(struct lirc_scancode)) + return -EINVAL; + + do { + if (kfifo_is_empty(&rcdev->scancodes)) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible(rcdev->wait_poll, + !kfifo_is_empty(&rcdev->scancodes) || + !rcdev->registered); + if (ret) + return ret; + } + + if (!rcdev->registered) + return -ENODEV; + + ret = mutex_lock_interruptible(&rcdev->lock); + if (ret) + return ret; + ret = kfifo_to_user(&rcdev->scancodes, buffer, length, &copied); + mutex_unlock(&rcdev->lock); + if (ret) + return ret; + } while (copied == 0); + + return copied; +} + +static ssize_t ir_lirc_read(struct file *file, char __user *buffer, + size_t length, loff_t *ppos) +{ + struct rc_dev *rcdev = file->private_data; + + if (rcdev->driver_type == RC_DRIVER_IR_RAW_TX) + return -EINVAL; + + if (!rcdev->registered) + return -ENODEV; + + if (rcdev->rec_mode == LIRC_MODE_MODE2) + return ir_lirc_read_mode2(file, buffer, length); + else /* LIRC_MODE_SCANCODE */ + return ir_lirc_read_scancode(file, buffer, length); +} + const struct file_operations lirc_fops = { .owner = THIS_MODULE, .write = ir_lirc_transmit_ir, -- cgit From 62d6f1994b41b9210b07ca453372797f59141e5c Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 24 Sep 2017 12:43:24 -0400 Subject: media: lirc: scancode rc devices should have a lirc device too Now that the lirc interface supports scancodes, RC scancode devices can also have a lirc device. The only receiving feature they will have enabled is LIRC_CAN_REC_SCANCODE. Note that CEC devices have no lirc device, since they can be controlled from their /dev/cecN chardev. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 817258c87b5c..8c5df6e8579e 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -304,6 +304,9 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, switch (cmd) { case LIRC_GET_FEATURES: + if (dev->driver_type == RC_DRIVER_SCANCODE) + val |= LIRC_CAN_REC_SCANCODE; + if (dev->driver_type == RC_DRIVER_IR_RAW) { val |= LIRC_CAN_REC_MODE2 | LIRC_CAN_REC_SCANCODE; if (dev->rx_resolution) @@ -344,11 +347,19 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, break; case LIRC_SET_REC_MODE: - if (dev->driver_type == RC_DRIVER_IR_RAW_TX) + switch (dev->driver_type) { + case RC_DRIVER_IR_RAW_TX: return -ENOTTY; - - if (!(val == LIRC_MODE_MODE2 || val == LIRC_MODE_SCANCODE)) - return -EINVAL; + case RC_DRIVER_SCANCODE: + if (val != LIRC_MODE_SCANCODE) + return -EINVAL; + break; + case RC_DRIVER_IR_RAW: + if (!(val == LIRC_MODE_MODE2 || + val == LIRC_MODE_SCANCODE)) + return -EINVAL; + break; + } dev->rec_mode = val; return 0; -- cgit From 42e0442f8a237d3de9ea3f2dd2be2739e6db7fdb Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 2 Nov 2017 16:39:16 -0400 Subject: media: rc: move ir-lirc-codec.c contents into lirc_dev.c Since removing the lirc kapi, ir-lirc-codec.c only contains lirc fops so the file name is no longer correct. By moving its content into lirc_dev.c the ugly extern struct lirc_fops is not longer needed, and everything lirc related is in one file. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 623 --------------------------------------- 1 file changed, 623 deletions(-) delete mode 100644 drivers/media/rc/ir-lirc-codec.c (limited to 'drivers/media/rc/ir-lirc-codec.c') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c deleted file mode 100644 index 8c5df6e8579e..000000000000 --- a/drivers/media/rc/ir-lirc-codec.c +++ /dev/null @@ -1,623 +0,0 @@ -/* ir-lirc-codec.c - rc-core to classic lirc interface bridge - * - * Copyright (C) 2010 by Jarod Wilson - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include "rc-core-priv.h" - -#define LIRCBUF_SIZE 256 - -/** - * ir_lirc_raw_event() - Send raw IR data to lirc to be relayed to userspace - * - * @dev: the struct rc_dev descriptor of the device - * @ev: the struct ir_raw_event descriptor of the pulse/space - */ -void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) -{ - int sample; - - /* Packet start */ - if (ev.reset) { - /* Userspace expects a long space event before the start of - * the signal to use as a sync. This may be done with repeat - * packets and normal samples. But if a reset has been sent - * then we assume that a long time has passed, so we send a - * space with the maximum time value. */ - sample = LIRC_SPACE(LIRC_VALUE_MASK); - IR_dprintk(2, "delivering reset sync space to lirc_dev\n"); - - /* Carrier reports */ - } else if (ev.carrier_report) { - sample = LIRC_FREQUENCY(ev.carrier); - IR_dprintk(2, "carrier report (freq: %d)\n", sample); - - /* Packet end */ - } else if (ev.timeout) { - - if (dev->gap) - return; - - dev->gap_start = ktime_get(); - dev->gap = true; - dev->gap_duration = ev.duration; - - if (!dev->send_timeout_reports) - return; - - sample = LIRC_TIMEOUT(ev.duration / 1000); - IR_dprintk(2, "timeout report (duration: %d)\n", sample); - - /* Normal sample */ - } else { - - if (dev->gap) { - dev->gap_duration += ktime_to_ns(ktime_sub(ktime_get(), - dev->gap_start)); - - /* Convert to ms and cap by LIRC_VALUE_MASK */ - do_div(dev->gap_duration, 1000); - dev->gap_duration = min_t(u64, dev->gap_duration, - LIRC_VALUE_MASK); - - kfifo_put(&dev->rawir, LIRC_SPACE(dev->gap_duration)); - dev->gap = false; - } - - sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) : - LIRC_SPACE(ev.duration / 1000); - IR_dprintk(2, "delivering %uus %s to lirc_dev\n", - TO_US(ev.duration), TO_STR(ev.pulse)); - } - - kfifo_put(&dev->rawir, sample); - wake_up_poll(&dev->wait_poll, POLLIN | POLLRDNORM); -} - -/** - * ir_lirc_scancode_event() - Send scancode data to lirc to be relayed to - * userspace - * @dev: the struct rc_dev descriptor of the device - * @lsc: the struct lirc_scancode describing the decoded scancode - */ -void ir_lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc) -{ - lsc->timestamp = ktime_get_ns(); - - if (kfifo_put(&dev->scancodes, *lsc)) - wake_up_poll(&dev->wait_poll, POLLIN | POLLRDNORM); -} -EXPORT_SYMBOL_GPL(ir_lirc_scancode_event); - -static int ir_lirc_open(struct inode *inode, struct file *file) -{ - struct rc_dev *dev = container_of(inode->i_cdev, struct rc_dev, - lirc_cdev); - int retval; - - retval = rc_open(dev); - if (retval) - return retval; - - retval = mutex_lock_interruptible(&dev->lock); - if (retval) - goto out_rc; - - if (!dev->registered) { - retval = -ENODEV; - goto out_unlock; - } - - if (dev->lirc_open) { - retval = -EBUSY; - goto out_unlock; - } - - if (dev->driver_type == RC_DRIVER_IR_RAW) - kfifo_reset_out(&dev->rawir); - if (dev->driver_type != RC_DRIVER_IR_RAW_TX) - kfifo_reset_out(&dev->scancodes); - - dev->lirc_open++; - file->private_data = dev; - - nonseekable_open(inode, file); - mutex_unlock(&dev->lock); - - return 0; - -out_unlock: - mutex_unlock(&dev->lock); -out_rc: - rc_close(dev); - return retval; -} - -static int ir_lirc_close(struct inode *inode, struct file *file) -{ - struct rc_dev *dev = file->private_data; - - mutex_lock(&dev->lock); - dev->lirc_open--; - mutex_unlock(&dev->lock); - - rc_close(dev); - - return 0; -} - -static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, - size_t n, loff_t *ppos) -{ - struct rc_dev *dev = file->private_data; - unsigned int *txbuf = NULL; - struct ir_raw_event *raw = NULL; - ssize_t ret = -EINVAL; - size_t count; - ktime_t start; - s64 towait; - unsigned int duration = 0; /* signal duration in us */ - int i; - - if (!dev->registered) - return -ENODEV; - - start = ktime_get(); - - if (!dev->tx_ir) { - ret = -EINVAL; - goto out; - } - - if (dev->send_mode == LIRC_MODE_SCANCODE) { - struct lirc_scancode scan; - - if (n != sizeof(scan)) - return -EINVAL; - - if (copy_from_user(&scan, buf, sizeof(scan))) - return -EFAULT; - - if (scan.flags || scan.keycode || scan.timestamp) - return -EINVAL; - - /* - * The scancode field in lirc_scancode is 64-bit simply - * to future-proof it, since there are IR protocols encode - * use more than 32 bits. For now only 32-bit protocols - * are supported. - */ - if (scan.scancode > U32_MAX || - !rc_validate_scancode(scan.rc_proto, scan.scancode)) - return -EINVAL; - - raw = kmalloc_array(LIRCBUF_SIZE, sizeof(*raw), GFP_KERNEL); - if (!raw) - return -ENOMEM; - - ret = ir_raw_encode_scancode(scan.rc_proto, scan.scancode, - raw, LIRCBUF_SIZE); - if (ret < 0) - goto out; - - count = ret; - - txbuf = kmalloc_array(count, sizeof(unsigned int), GFP_KERNEL); - if (!txbuf) { - ret = -ENOMEM; - goto out; - } - - for (i = 0; i < count; i++) - /* Convert from NS to US */ - txbuf[i] = DIV_ROUND_UP(raw[i].duration, 1000); - - if (dev->s_tx_carrier) { - int carrier = ir_raw_encode_carrier(scan.rc_proto); - - if (carrier > 0) - dev->s_tx_carrier(dev, carrier); - } - } else { - if (n < sizeof(unsigned int) || n % sizeof(unsigned int)) - return -EINVAL; - - count = n / sizeof(unsigned int); - if (count > LIRCBUF_SIZE || count % 2 == 0) - return -EINVAL; - - txbuf = memdup_user(buf, n); - if (IS_ERR(txbuf)) - return PTR_ERR(txbuf); - } - - for (i = 0; i < count; i++) { - if (txbuf[i] > IR_MAX_DURATION / 1000 - duration || !txbuf[i]) { - ret = -EINVAL; - goto out; - } - - duration += txbuf[i]; - } - - ret = dev->tx_ir(dev, txbuf, count); - if (ret < 0) - goto out; - - if (dev->send_mode == LIRC_MODE_SCANCODE) { - ret = n; - } else { - for (duration = i = 0; i < ret; i++) - duration += txbuf[i]; - - ret *= sizeof(unsigned int); - - /* - * The lircd gap calculation expects the write function to - * wait for the actual IR signal to be transmitted before - * returning. - */ - towait = ktime_us_delta(ktime_add_us(start, duration), - ktime_get()); - if (towait > 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(usecs_to_jiffies(towait)); - } - } - -out: - kfree(txbuf); - kfree(raw); - return ret; -} - -static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, - unsigned long arg) -{ - struct rc_dev *dev = filep->private_data; - u32 __user *argp = (u32 __user *)(arg); - int ret = 0; - __u32 val = 0, tmp; - - if (_IOC_DIR(cmd) & _IOC_WRITE) { - ret = get_user(val, argp); - if (ret) - return ret; - } - - if (!dev->registered) - return -ENODEV; - - switch (cmd) { - case LIRC_GET_FEATURES: - if (dev->driver_type == RC_DRIVER_SCANCODE) - val |= LIRC_CAN_REC_SCANCODE; - - if (dev->driver_type == RC_DRIVER_IR_RAW) { - val |= LIRC_CAN_REC_MODE2 | LIRC_CAN_REC_SCANCODE; - if (dev->rx_resolution) - val |= LIRC_CAN_GET_REC_RESOLUTION; - } - - if (dev->tx_ir) { - val |= LIRC_CAN_SEND_PULSE | LIRC_CAN_SEND_SCANCODE; - if (dev->s_tx_mask) - val |= LIRC_CAN_SET_TRANSMITTER_MASK; - if (dev->s_tx_carrier) - val |= LIRC_CAN_SET_SEND_CARRIER; - if (dev->s_tx_duty_cycle) - val |= LIRC_CAN_SET_SEND_DUTY_CYCLE; - } - - if (dev->s_rx_carrier_range) - val |= LIRC_CAN_SET_REC_CARRIER | - LIRC_CAN_SET_REC_CARRIER_RANGE; - - if (dev->s_learning_mode) - val |= LIRC_CAN_USE_WIDEBAND_RECEIVER; - - if (dev->s_carrier_report) - val |= LIRC_CAN_MEASURE_CARRIER; - - if (dev->max_timeout) - val |= LIRC_CAN_SET_REC_TIMEOUT; - - break; - - /* mode support */ - case LIRC_GET_REC_MODE: - if (dev->driver_type == RC_DRIVER_IR_RAW_TX) - return -ENOTTY; - - val = dev->rec_mode; - break; - - case LIRC_SET_REC_MODE: - switch (dev->driver_type) { - case RC_DRIVER_IR_RAW_TX: - return -ENOTTY; - case RC_DRIVER_SCANCODE: - if (val != LIRC_MODE_SCANCODE) - return -EINVAL; - break; - case RC_DRIVER_IR_RAW: - if (!(val == LIRC_MODE_MODE2 || - val == LIRC_MODE_SCANCODE)) - return -EINVAL; - break; - } - - dev->rec_mode = val; - return 0; - - case LIRC_GET_SEND_MODE: - if (!dev->tx_ir) - return -ENOTTY; - - val = dev->send_mode; - break; - - case LIRC_SET_SEND_MODE: - if (!dev->tx_ir) - return -ENOTTY; - - if (!(val == LIRC_MODE_PULSE || val == LIRC_MODE_SCANCODE)) - return -EINVAL; - - dev->send_mode = val; - return 0; - - /* TX settings */ - case LIRC_SET_TRANSMITTER_MASK: - if (!dev->s_tx_mask) - return -ENOTTY; - - return dev->s_tx_mask(dev, val); - - case LIRC_SET_SEND_CARRIER: - if (!dev->s_tx_carrier) - return -ENOTTY; - - return dev->s_tx_carrier(dev, val); - - case LIRC_SET_SEND_DUTY_CYCLE: - if (!dev->s_tx_duty_cycle) - return -ENOTTY; - - if (val <= 0 || val >= 100) - return -EINVAL; - - return dev->s_tx_duty_cycle(dev, val); - - /* RX settings */ - case LIRC_SET_REC_CARRIER: - if (!dev->s_rx_carrier_range) - return -ENOTTY; - - if (val <= 0) - return -EINVAL; - - return dev->s_rx_carrier_range(dev, - dev->carrier_low, - val); - - case LIRC_SET_REC_CARRIER_RANGE: - if (!dev->s_rx_carrier_range) - return -ENOTTY; - - if (val <= 0) - return -EINVAL; - - dev->carrier_low = val; - return 0; - - case LIRC_GET_REC_RESOLUTION: - if (!dev->rx_resolution) - return -ENOTTY; - - val = dev->rx_resolution / 1000; - break; - - case LIRC_SET_WIDEBAND_RECEIVER: - if (!dev->s_learning_mode) - return -ENOTTY; - - return dev->s_learning_mode(dev, !!val); - - case LIRC_SET_MEASURE_CARRIER_MODE: - if (!dev->s_carrier_report) - return -ENOTTY; - - return dev->s_carrier_report(dev, !!val); - - /* Generic timeout support */ - case LIRC_GET_MIN_TIMEOUT: - if (!dev->max_timeout) - return -ENOTTY; - val = DIV_ROUND_UP(dev->min_timeout, 1000); - break; - - case LIRC_GET_MAX_TIMEOUT: - if (!dev->max_timeout) - return -ENOTTY; - val = dev->max_timeout / 1000; - break; - - case LIRC_SET_REC_TIMEOUT: - if (!dev->max_timeout) - return -ENOTTY; - - /* Check for multiply overflow */ - if (val > U32_MAX / 1000) - return -EINVAL; - - tmp = val * 1000; - - if (tmp < dev->min_timeout || tmp > dev->max_timeout) - return -EINVAL; - - if (dev->s_timeout) - ret = dev->s_timeout(dev, tmp); - if (!ret) - dev->timeout = tmp; - break; - - case LIRC_SET_REC_TIMEOUT_REPORTS: - if (!dev->timeout) - return -ENOTTY; - - dev->send_timeout_reports = !!val; - break; - - default: - return -ENOTTY; - } - - if (_IOC_DIR(cmd) & _IOC_READ) - ret = put_user(val, argp); - - return ret; -} - -static unsigned int ir_lirc_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct rc_dev *rcdev = file->private_data; - unsigned int events = 0; - - poll_wait(file, &rcdev->wait_poll, wait); - - if (!rcdev->registered) { - events = POLLHUP | POLLERR; - } else if (rcdev->driver_type != RC_DRIVER_IR_RAW_TX) { - if (rcdev->rec_mode == LIRC_MODE_SCANCODE && - !kfifo_is_empty(&rcdev->scancodes)) - events = POLLIN | POLLRDNORM; - - if (rcdev->rec_mode == LIRC_MODE_MODE2 && - !kfifo_is_empty(&rcdev->rawir)) - events = POLLIN | POLLRDNORM; - } - - return events; -} - -static ssize_t ir_lirc_read_mode2(struct file *file, char __user *buffer, - size_t length) -{ - struct rc_dev *rcdev = file->private_data; - unsigned int copied; - int ret; - - if (length < sizeof(unsigned int) || length % sizeof(unsigned int)) - return -EINVAL; - - do { - if (kfifo_is_empty(&rcdev->rawir)) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - ret = wait_event_interruptible(rcdev->wait_poll, - !kfifo_is_empty(&rcdev->rawir) || - !rcdev->registered); - if (ret) - return ret; - } - - if (!rcdev->registered) - return -ENODEV; - - ret = mutex_lock_interruptible(&rcdev->lock); - if (ret) - return ret; - ret = kfifo_to_user(&rcdev->rawir, buffer, length, &copied); - mutex_unlock(&rcdev->lock); - if (ret) - return ret; - } while (copied == 0); - - return copied; -} - -static ssize_t ir_lirc_read_scancode(struct file *file, char __user *buffer, - size_t length) -{ - struct rc_dev *rcdev = file->private_data; - unsigned int copied; - int ret; - - if (length < sizeof(struct lirc_scancode) || - length % sizeof(struct lirc_scancode)) - return -EINVAL; - - do { - if (kfifo_is_empty(&rcdev->scancodes)) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - ret = wait_event_interruptible(rcdev->wait_poll, - !kfifo_is_empty(&rcdev->scancodes) || - !rcdev->registered); - if (ret) - return ret; - } - - if (!rcdev->registered) - return -ENODEV; - - ret = mutex_lock_interruptible(&rcdev->lock); - if (ret) - return ret; - ret = kfifo_to_user(&rcdev->scancodes, buffer, length, &copied); - mutex_unlock(&rcdev->lock); - if (ret) - return ret; - } while (copied == 0); - - return copied; -} - -static ssize_t ir_lirc_read(struct file *file, char __user *buffer, - size_t length, loff_t *ppos) -{ - struct rc_dev *rcdev = file->private_data; - - if (rcdev->driver_type == RC_DRIVER_IR_RAW_TX) - return -EINVAL; - - if (!rcdev->registered) - return -ENODEV; - - if (rcdev->rec_mode == LIRC_MODE_MODE2) - return ir_lirc_read_mode2(file, buffer, length); - else /* LIRC_MODE_SCANCODE */ - return ir_lirc_read_scancode(file, buffer, length); -} - -const struct file_operations lirc_fops = { - .owner = THIS_MODULE, - .write = ir_lirc_transmit_ir, - .unlocked_ioctl = ir_lirc_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ir_lirc_ioctl, -#endif - .read = ir_lirc_read, - .poll = ir_lirc_poll, - .open = ir_lirc_open, - .release = ir_lirc_close, - .llseek = no_llseek, -}; -- cgit