132cf86f6SMauro Carvalho Chehab /* 232cf86f6SMauro Carvalho Chehab * LIRC base driver 332cf86f6SMauro Carvalho Chehab * 432cf86f6SMauro Carvalho Chehab * by Artur Lipowski <alipowski@interia.pl> 532cf86f6SMauro Carvalho Chehab * 632cf86f6SMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 732cf86f6SMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 832cf86f6SMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License, or 932cf86f6SMauro Carvalho Chehab * (at your option) any later version. 1032cf86f6SMauro Carvalho Chehab * 1132cf86f6SMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 1232cf86f6SMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 1332cf86f6SMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1432cf86f6SMauro Carvalho Chehab * GNU General Public License for more details. 1532cf86f6SMauro Carvalho Chehab * 1632cf86f6SMauro Carvalho Chehab */ 1732cf86f6SMauro Carvalho Chehab 183fac0314SAndi Shyti #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 193fac0314SAndi Shyti 2032cf86f6SMauro Carvalho Chehab #include <linux/module.h> 2132cf86f6SMauro Carvalho Chehab #include <linux/mutex.h> 2232cf86f6SMauro Carvalho Chehab #include <linux/device.h> 2346c8f477SDavid Härdeman #include <linux/idr.h> 24a6ddd4feSSean Young #include <linux/poll.h> 2542e0442fSSean Young #include <linux/sched.h> 2642e0442fSSean Young #include <linux/wait.h> 2732cf86f6SMauro Carvalho Chehab 28a60d64b1SSean Young #include "rc-core-priv.h" 29*aefb5e34SSean Young #include <uapi/linux/lirc.h> 3032cf86f6SMauro Carvalho Chehab 3132cf86f6SMauro Carvalho Chehab #define LOGHEAD "lirc_dev (%s[%d]): " 3242e0442fSSean Young #define LIRCBUF_SIZE 256 3332cf86f6SMauro Carvalho Chehab 3432cf86f6SMauro Carvalho Chehab static dev_t lirc_base_dev; 3532cf86f6SMauro Carvalho Chehab 3646c8f477SDavid Härdeman /* Used to keep track of allocated lirc devices */ 3746c8f477SDavid Härdeman static DEFINE_IDA(lirc_ida); 3832cf86f6SMauro Carvalho Chehab 3932cf86f6SMauro Carvalho Chehab /* Only used for sysfs but defined to void otherwise */ 4032cf86f6SMauro Carvalho Chehab static struct class *lirc_class; 4132cf86f6SMauro Carvalho Chehab 4242e0442fSSean Young /** 4342e0442fSSean Young * ir_lirc_raw_event() - Send raw IR data to lirc to be relayed to userspace 4442e0442fSSean Young * 4542e0442fSSean Young * @dev: the struct rc_dev descriptor of the device 4642e0442fSSean Young * @ev: the struct ir_raw_event descriptor of the pulse/space 4742e0442fSSean Young */ 4842e0442fSSean Young void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) 4942e0442fSSean Young { 5042e0442fSSean Young int sample; 5142e0442fSSean Young 5242e0442fSSean Young /* Packet start */ 5342e0442fSSean Young if (ev.reset) { 5442e0442fSSean Young /* 5542e0442fSSean Young * Userspace expects a long space event before the start of 5642e0442fSSean Young * the signal to use as a sync. This may be done with repeat 5742e0442fSSean Young * packets and normal samples. But if a reset has been sent 5842e0442fSSean Young * then we assume that a long time has passed, so we send a 5942e0442fSSean Young * space with the maximum time value. 6042e0442fSSean Young */ 6142e0442fSSean Young sample = LIRC_SPACE(LIRC_VALUE_MASK); 6242e0442fSSean Young IR_dprintk(2, "delivering reset sync space to lirc_dev\n"); 6342e0442fSSean Young 6442e0442fSSean Young /* Carrier reports */ 6542e0442fSSean Young } else if (ev.carrier_report) { 6642e0442fSSean Young sample = LIRC_FREQUENCY(ev.carrier); 6742e0442fSSean Young IR_dprintk(2, "carrier report (freq: %d)\n", sample); 6842e0442fSSean Young 6942e0442fSSean Young /* Packet end */ 7042e0442fSSean Young } else if (ev.timeout) { 7142e0442fSSean Young if (dev->gap) 7242e0442fSSean Young return; 7342e0442fSSean Young 7442e0442fSSean Young dev->gap_start = ktime_get(); 7542e0442fSSean Young dev->gap = true; 7642e0442fSSean Young dev->gap_duration = ev.duration; 7742e0442fSSean Young 7842e0442fSSean Young if (!dev->send_timeout_reports) 7942e0442fSSean Young return; 8042e0442fSSean Young 8142e0442fSSean Young sample = LIRC_TIMEOUT(ev.duration / 1000); 8242e0442fSSean Young IR_dprintk(2, "timeout report (duration: %d)\n", sample); 8342e0442fSSean Young 8442e0442fSSean Young /* Normal sample */ 8542e0442fSSean Young } else { 8642e0442fSSean Young if (dev->gap) { 8742e0442fSSean Young dev->gap_duration += ktime_to_ns(ktime_sub(ktime_get(), 8842e0442fSSean Young dev->gap_start)); 8942e0442fSSean Young 9042e0442fSSean Young /* Convert to ms and cap by LIRC_VALUE_MASK */ 9142e0442fSSean Young do_div(dev->gap_duration, 1000); 9242e0442fSSean Young dev->gap_duration = min_t(u64, dev->gap_duration, 9342e0442fSSean Young LIRC_VALUE_MASK); 9442e0442fSSean Young 9542e0442fSSean Young kfifo_put(&dev->rawir, LIRC_SPACE(dev->gap_duration)); 9642e0442fSSean Young dev->gap = false; 9742e0442fSSean Young } 9842e0442fSSean Young 9942e0442fSSean Young sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) : 10042e0442fSSean Young LIRC_SPACE(ev.duration / 1000); 10142e0442fSSean Young IR_dprintk(2, "delivering %uus %s to lirc_dev\n", 10242e0442fSSean Young TO_US(ev.duration), TO_STR(ev.pulse)); 10342e0442fSSean Young } 10442e0442fSSean Young 10542e0442fSSean Young kfifo_put(&dev->rawir, sample); 10642e0442fSSean Young wake_up_poll(&dev->wait_poll, POLLIN | POLLRDNORM); 10742e0442fSSean Young } 10842e0442fSSean Young 10942e0442fSSean Young /** 11042e0442fSSean Young * ir_lirc_scancode_event() - Send scancode data to lirc to be relayed to 11142e0442fSSean Young * userspace 11242e0442fSSean Young * @dev: the struct rc_dev descriptor of the device 11342e0442fSSean Young * @lsc: the struct lirc_scancode describing the decoded scancode 11442e0442fSSean Young */ 11542e0442fSSean Young void ir_lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc) 11642e0442fSSean Young { 11742e0442fSSean Young lsc->timestamp = ktime_get_ns(); 11842e0442fSSean Young 11942e0442fSSean Young if (kfifo_put(&dev->scancodes, *lsc)) 12042e0442fSSean Young wake_up_poll(&dev->wait_poll, POLLIN | POLLRDNORM); 12142e0442fSSean Young } 12242e0442fSSean Young EXPORT_SYMBOL_GPL(ir_lirc_scancode_event); 12342e0442fSSean Young 12442e0442fSSean Young static int ir_lirc_open(struct inode *inode, struct file *file) 12542e0442fSSean Young { 12642e0442fSSean Young struct rc_dev *dev = container_of(inode->i_cdev, struct rc_dev, 12742e0442fSSean Young lirc_cdev); 12842e0442fSSean Young int retval; 12942e0442fSSean Young 13042e0442fSSean Young retval = rc_open(dev); 13142e0442fSSean Young if (retval) 13242e0442fSSean Young return retval; 13342e0442fSSean Young 13442e0442fSSean Young retval = mutex_lock_interruptible(&dev->lock); 13542e0442fSSean Young if (retval) 13642e0442fSSean Young goto out_rc; 13742e0442fSSean Young 13842e0442fSSean Young if (!dev->registered) { 13942e0442fSSean Young retval = -ENODEV; 14042e0442fSSean Young goto out_unlock; 14142e0442fSSean Young } 14242e0442fSSean Young 14342e0442fSSean Young if (dev->lirc_open) { 14442e0442fSSean Young retval = -EBUSY; 14542e0442fSSean Young goto out_unlock; 14642e0442fSSean Young } 14742e0442fSSean Young 14842e0442fSSean Young if (dev->driver_type == RC_DRIVER_IR_RAW) 14942e0442fSSean Young kfifo_reset_out(&dev->rawir); 15042e0442fSSean Young if (dev->driver_type != RC_DRIVER_IR_RAW_TX) 15142e0442fSSean Young kfifo_reset_out(&dev->scancodes); 15242e0442fSSean Young 15342e0442fSSean Young dev->lirc_open++; 15442e0442fSSean Young file->private_data = dev; 15542e0442fSSean Young 15642e0442fSSean Young nonseekable_open(inode, file); 15742e0442fSSean Young mutex_unlock(&dev->lock); 15842e0442fSSean Young 15942e0442fSSean Young return 0; 16042e0442fSSean Young 16142e0442fSSean Young out_unlock: 16242e0442fSSean Young mutex_unlock(&dev->lock); 16342e0442fSSean Young out_rc: 16442e0442fSSean Young rc_close(dev); 16542e0442fSSean Young return retval; 16642e0442fSSean Young } 16742e0442fSSean Young 16842e0442fSSean Young static int ir_lirc_close(struct inode *inode, struct file *file) 16942e0442fSSean Young { 17042e0442fSSean Young struct rc_dev *dev = file->private_data; 17142e0442fSSean Young 17242e0442fSSean Young mutex_lock(&dev->lock); 17342e0442fSSean Young dev->lirc_open--; 17442e0442fSSean Young mutex_unlock(&dev->lock); 17542e0442fSSean Young 17642e0442fSSean Young rc_close(dev); 17742e0442fSSean Young 17842e0442fSSean Young return 0; 17942e0442fSSean Young } 18042e0442fSSean Young 18142e0442fSSean Young static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, 18242e0442fSSean Young size_t n, loff_t *ppos) 18342e0442fSSean Young { 18442e0442fSSean Young struct rc_dev *dev = file->private_data; 18542e0442fSSean Young unsigned int *txbuf = NULL; 18642e0442fSSean Young struct ir_raw_event *raw = NULL; 18742e0442fSSean Young ssize_t ret = -EINVAL; 18842e0442fSSean Young size_t count; 18942e0442fSSean Young ktime_t start; 19042e0442fSSean Young s64 towait; 19142e0442fSSean Young unsigned int duration = 0; /* signal duration in us */ 19242e0442fSSean Young int i; 19342e0442fSSean Young 19442e0442fSSean Young if (!dev->registered) 19542e0442fSSean Young return -ENODEV; 19642e0442fSSean Young 19742e0442fSSean Young start = ktime_get(); 19842e0442fSSean Young 19942e0442fSSean Young if (!dev->tx_ir) { 20042e0442fSSean Young ret = -EINVAL; 20142e0442fSSean Young goto out; 20242e0442fSSean Young } 20342e0442fSSean Young 20442e0442fSSean Young if (dev->send_mode == LIRC_MODE_SCANCODE) { 20542e0442fSSean Young struct lirc_scancode scan; 20642e0442fSSean Young 20742e0442fSSean Young if (n != sizeof(scan)) 20842e0442fSSean Young return -EINVAL; 20942e0442fSSean Young 21042e0442fSSean Young if (copy_from_user(&scan, buf, sizeof(scan))) 21142e0442fSSean Young return -EFAULT; 21242e0442fSSean Young 21342e0442fSSean Young if (scan.flags || scan.keycode || scan.timestamp) 21442e0442fSSean Young return -EINVAL; 21542e0442fSSean Young 21642e0442fSSean Young /* 21742e0442fSSean Young * The scancode field in lirc_scancode is 64-bit simply 21842e0442fSSean Young * to future-proof it, since there are IR protocols encode 21942e0442fSSean Young * use more than 32 bits. For now only 32-bit protocols 22042e0442fSSean Young * are supported. 22142e0442fSSean Young */ 22242e0442fSSean Young if (scan.scancode > U32_MAX || 22342e0442fSSean Young !rc_validate_scancode(scan.rc_proto, scan.scancode)) 22442e0442fSSean Young return -EINVAL; 22542e0442fSSean Young 22642e0442fSSean Young raw = kmalloc_array(LIRCBUF_SIZE, sizeof(*raw), GFP_KERNEL); 22742e0442fSSean Young if (!raw) 22842e0442fSSean Young return -ENOMEM; 22942e0442fSSean Young 23042e0442fSSean Young ret = ir_raw_encode_scancode(scan.rc_proto, scan.scancode, 23142e0442fSSean Young raw, LIRCBUF_SIZE); 23242e0442fSSean Young if (ret < 0) 23342e0442fSSean Young goto out; 23442e0442fSSean Young 23542e0442fSSean Young count = ret; 23642e0442fSSean Young 23742e0442fSSean Young txbuf = kmalloc_array(count, sizeof(unsigned int), GFP_KERNEL); 23842e0442fSSean Young if (!txbuf) { 23942e0442fSSean Young ret = -ENOMEM; 24042e0442fSSean Young goto out; 24142e0442fSSean Young } 24242e0442fSSean Young 24342e0442fSSean Young for (i = 0; i < count; i++) 24442e0442fSSean Young /* Convert from NS to US */ 24542e0442fSSean Young txbuf[i] = DIV_ROUND_UP(raw[i].duration, 1000); 24642e0442fSSean Young 24742e0442fSSean Young if (dev->s_tx_carrier) { 24842e0442fSSean Young int carrier = ir_raw_encode_carrier(scan.rc_proto); 24942e0442fSSean Young 25042e0442fSSean Young if (carrier > 0) 25142e0442fSSean Young dev->s_tx_carrier(dev, carrier); 25242e0442fSSean Young } 25342e0442fSSean Young } else { 25442e0442fSSean Young if (n < sizeof(unsigned int) || n % sizeof(unsigned int)) 25542e0442fSSean Young return -EINVAL; 25642e0442fSSean Young 25742e0442fSSean Young count = n / sizeof(unsigned int); 25842e0442fSSean Young if (count > LIRCBUF_SIZE || count % 2 == 0) 25942e0442fSSean Young return -EINVAL; 26042e0442fSSean Young 26142e0442fSSean Young txbuf = memdup_user(buf, n); 26242e0442fSSean Young if (IS_ERR(txbuf)) 26342e0442fSSean Young return PTR_ERR(txbuf); 26442e0442fSSean Young } 26542e0442fSSean Young 26642e0442fSSean Young for (i = 0; i < count; i++) { 26742e0442fSSean Young if (txbuf[i] > IR_MAX_DURATION / 1000 - duration || !txbuf[i]) { 26842e0442fSSean Young ret = -EINVAL; 26942e0442fSSean Young goto out; 27042e0442fSSean Young } 27142e0442fSSean Young 27242e0442fSSean Young duration += txbuf[i]; 27342e0442fSSean Young } 27442e0442fSSean Young 27542e0442fSSean Young ret = dev->tx_ir(dev, txbuf, count); 27642e0442fSSean Young if (ret < 0) 27742e0442fSSean Young goto out; 27842e0442fSSean Young 27942e0442fSSean Young if (dev->send_mode == LIRC_MODE_SCANCODE) { 28042e0442fSSean Young ret = n; 28142e0442fSSean Young } else { 28242e0442fSSean Young for (duration = i = 0; i < ret; i++) 28342e0442fSSean Young duration += txbuf[i]; 28442e0442fSSean Young 28542e0442fSSean Young ret *= sizeof(unsigned int); 28642e0442fSSean Young 28742e0442fSSean Young /* 28842e0442fSSean Young * The lircd gap calculation expects the write function to 28942e0442fSSean Young * wait for the actual IR signal to be transmitted before 29042e0442fSSean Young * returning. 29142e0442fSSean Young */ 29242e0442fSSean Young towait = ktime_us_delta(ktime_add_us(start, duration), 29342e0442fSSean Young ktime_get()); 29442e0442fSSean Young if (towait > 0) { 29542e0442fSSean Young set_current_state(TASK_INTERRUPTIBLE); 29642e0442fSSean Young schedule_timeout(usecs_to_jiffies(towait)); 29742e0442fSSean Young } 29842e0442fSSean Young } 29942e0442fSSean Young 30042e0442fSSean Young out: 30142e0442fSSean Young kfree(txbuf); 30242e0442fSSean Young kfree(raw); 30342e0442fSSean Young return ret; 30442e0442fSSean Young } 30542e0442fSSean Young 30642e0442fSSean Young static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, 30742e0442fSSean Young unsigned long arg) 30842e0442fSSean Young { 30942e0442fSSean Young struct rc_dev *dev = filep->private_data; 31042e0442fSSean Young u32 __user *argp = (u32 __user *)(arg); 31142e0442fSSean Young int ret = 0; 31242e0442fSSean Young __u32 val = 0, tmp; 31342e0442fSSean Young 31442e0442fSSean Young if (_IOC_DIR(cmd) & _IOC_WRITE) { 31542e0442fSSean Young ret = get_user(val, argp); 31642e0442fSSean Young if (ret) 31742e0442fSSean Young return ret; 31842e0442fSSean Young } 31942e0442fSSean Young 32042e0442fSSean Young if (!dev->registered) 32142e0442fSSean Young return -ENODEV; 32242e0442fSSean Young 32342e0442fSSean Young switch (cmd) { 32442e0442fSSean Young case LIRC_GET_FEATURES: 32542e0442fSSean Young if (dev->driver_type == RC_DRIVER_SCANCODE) 32642e0442fSSean Young val |= LIRC_CAN_REC_SCANCODE; 32742e0442fSSean Young 32842e0442fSSean Young if (dev->driver_type == RC_DRIVER_IR_RAW) { 32942e0442fSSean Young val |= LIRC_CAN_REC_MODE2 | LIRC_CAN_REC_SCANCODE; 33042e0442fSSean Young if (dev->rx_resolution) 33142e0442fSSean Young val |= LIRC_CAN_GET_REC_RESOLUTION; 33242e0442fSSean Young } 33342e0442fSSean Young 33442e0442fSSean Young if (dev->tx_ir) { 33542e0442fSSean Young val |= LIRC_CAN_SEND_PULSE | LIRC_CAN_SEND_SCANCODE; 33642e0442fSSean Young if (dev->s_tx_mask) 33742e0442fSSean Young val |= LIRC_CAN_SET_TRANSMITTER_MASK; 33842e0442fSSean Young if (dev->s_tx_carrier) 33942e0442fSSean Young val |= LIRC_CAN_SET_SEND_CARRIER; 34042e0442fSSean Young if (dev->s_tx_duty_cycle) 34142e0442fSSean Young val |= LIRC_CAN_SET_SEND_DUTY_CYCLE; 34242e0442fSSean Young } 34342e0442fSSean Young 34442e0442fSSean Young if (dev->s_rx_carrier_range) 34542e0442fSSean Young val |= LIRC_CAN_SET_REC_CARRIER | 34642e0442fSSean Young LIRC_CAN_SET_REC_CARRIER_RANGE; 34742e0442fSSean Young 34842e0442fSSean Young if (dev->s_learning_mode) 34942e0442fSSean Young val |= LIRC_CAN_USE_WIDEBAND_RECEIVER; 35042e0442fSSean Young 35142e0442fSSean Young if (dev->s_carrier_report) 35242e0442fSSean Young val |= LIRC_CAN_MEASURE_CARRIER; 35342e0442fSSean Young 35442e0442fSSean Young if (dev->max_timeout) 35542e0442fSSean Young val |= LIRC_CAN_SET_REC_TIMEOUT; 35642e0442fSSean Young 35742e0442fSSean Young break; 35842e0442fSSean Young 35942e0442fSSean Young /* mode support */ 36042e0442fSSean Young case LIRC_GET_REC_MODE: 36142e0442fSSean Young if (dev->driver_type == RC_DRIVER_IR_RAW_TX) 36242e0442fSSean Young return -ENOTTY; 36342e0442fSSean Young 36442e0442fSSean Young val = dev->rec_mode; 36542e0442fSSean Young break; 36642e0442fSSean Young 36742e0442fSSean Young case LIRC_SET_REC_MODE: 36842e0442fSSean Young switch (dev->driver_type) { 36942e0442fSSean Young case RC_DRIVER_IR_RAW_TX: 37042e0442fSSean Young return -ENOTTY; 37142e0442fSSean Young case RC_DRIVER_SCANCODE: 37242e0442fSSean Young if (val != LIRC_MODE_SCANCODE) 37342e0442fSSean Young return -EINVAL; 37442e0442fSSean Young break; 37542e0442fSSean Young case RC_DRIVER_IR_RAW: 37642e0442fSSean Young if (!(val == LIRC_MODE_MODE2 || 37742e0442fSSean Young val == LIRC_MODE_SCANCODE)) 37842e0442fSSean Young return -EINVAL; 37942e0442fSSean Young break; 38042e0442fSSean Young } 38142e0442fSSean Young 38242e0442fSSean Young dev->rec_mode = val; 38342e0442fSSean Young return 0; 38442e0442fSSean Young 38542e0442fSSean Young case LIRC_GET_SEND_MODE: 38642e0442fSSean Young if (!dev->tx_ir) 38742e0442fSSean Young return -ENOTTY; 38842e0442fSSean Young 38942e0442fSSean Young val = dev->send_mode; 39042e0442fSSean Young break; 39142e0442fSSean Young 39242e0442fSSean Young case LIRC_SET_SEND_MODE: 39342e0442fSSean Young if (!dev->tx_ir) 39442e0442fSSean Young return -ENOTTY; 39542e0442fSSean Young 39642e0442fSSean Young if (!(val == LIRC_MODE_PULSE || val == LIRC_MODE_SCANCODE)) 39742e0442fSSean Young return -EINVAL; 39842e0442fSSean Young 39942e0442fSSean Young dev->send_mode = val; 40042e0442fSSean Young return 0; 40142e0442fSSean Young 40242e0442fSSean Young /* TX settings */ 40342e0442fSSean Young case LIRC_SET_TRANSMITTER_MASK: 40442e0442fSSean Young if (!dev->s_tx_mask) 40542e0442fSSean Young return -ENOTTY; 40642e0442fSSean Young 40742e0442fSSean Young return dev->s_tx_mask(dev, val); 40842e0442fSSean Young 40942e0442fSSean Young case LIRC_SET_SEND_CARRIER: 41042e0442fSSean Young if (!dev->s_tx_carrier) 41142e0442fSSean Young return -ENOTTY; 41242e0442fSSean Young 41342e0442fSSean Young return dev->s_tx_carrier(dev, val); 41442e0442fSSean Young 41542e0442fSSean Young case LIRC_SET_SEND_DUTY_CYCLE: 41642e0442fSSean Young if (!dev->s_tx_duty_cycle) 41742e0442fSSean Young return -ENOTTY; 41842e0442fSSean Young 41942e0442fSSean Young if (val <= 0 || val >= 100) 42042e0442fSSean Young return -EINVAL; 42142e0442fSSean Young 42242e0442fSSean Young return dev->s_tx_duty_cycle(dev, val); 42342e0442fSSean Young 42442e0442fSSean Young /* RX settings */ 42542e0442fSSean Young case LIRC_SET_REC_CARRIER: 42642e0442fSSean Young if (!dev->s_rx_carrier_range) 42742e0442fSSean Young return -ENOTTY; 42842e0442fSSean Young 42942e0442fSSean Young if (val <= 0) 43042e0442fSSean Young return -EINVAL; 43142e0442fSSean Young 43242e0442fSSean Young return dev->s_rx_carrier_range(dev, 43342e0442fSSean Young dev->carrier_low, 43442e0442fSSean Young val); 43542e0442fSSean Young 43642e0442fSSean Young case LIRC_SET_REC_CARRIER_RANGE: 43742e0442fSSean Young if (!dev->s_rx_carrier_range) 43842e0442fSSean Young return -ENOTTY; 43942e0442fSSean Young 44042e0442fSSean Young if (val <= 0) 44142e0442fSSean Young return -EINVAL; 44242e0442fSSean Young 44342e0442fSSean Young dev->carrier_low = val; 44442e0442fSSean Young return 0; 44542e0442fSSean Young 44642e0442fSSean Young case LIRC_GET_REC_RESOLUTION: 44742e0442fSSean Young if (!dev->rx_resolution) 44842e0442fSSean Young return -ENOTTY; 44942e0442fSSean Young 45042e0442fSSean Young val = dev->rx_resolution / 1000; 45142e0442fSSean Young break; 45242e0442fSSean Young 45342e0442fSSean Young case LIRC_SET_WIDEBAND_RECEIVER: 45442e0442fSSean Young if (!dev->s_learning_mode) 45542e0442fSSean Young return -ENOTTY; 45642e0442fSSean Young 45742e0442fSSean Young return dev->s_learning_mode(dev, !!val); 45842e0442fSSean Young 45942e0442fSSean Young case LIRC_SET_MEASURE_CARRIER_MODE: 46042e0442fSSean Young if (!dev->s_carrier_report) 46142e0442fSSean Young return -ENOTTY; 46242e0442fSSean Young 46342e0442fSSean Young return dev->s_carrier_report(dev, !!val); 46442e0442fSSean Young 46542e0442fSSean Young /* Generic timeout support */ 46642e0442fSSean Young case LIRC_GET_MIN_TIMEOUT: 46742e0442fSSean Young if (!dev->max_timeout) 46842e0442fSSean Young return -ENOTTY; 46942e0442fSSean Young val = DIV_ROUND_UP(dev->min_timeout, 1000); 47042e0442fSSean Young break; 47142e0442fSSean Young 47242e0442fSSean Young case LIRC_GET_MAX_TIMEOUT: 47342e0442fSSean Young if (!dev->max_timeout) 47442e0442fSSean Young return -ENOTTY; 47542e0442fSSean Young val = dev->max_timeout / 1000; 47642e0442fSSean Young break; 47742e0442fSSean Young 47842e0442fSSean Young case LIRC_SET_REC_TIMEOUT: 47942e0442fSSean Young if (!dev->max_timeout) 48042e0442fSSean Young return -ENOTTY; 48142e0442fSSean Young 48242e0442fSSean Young /* Check for multiply overflow */ 48342e0442fSSean Young if (val > U32_MAX / 1000) 48442e0442fSSean Young return -EINVAL; 48542e0442fSSean Young 48642e0442fSSean Young tmp = val * 1000; 48742e0442fSSean Young 48842e0442fSSean Young if (tmp < dev->min_timeout || tmp > dev->max_timeout) 48942e0442fSSean Young return -EINVAL; 49042e0442fSSean Young 49142e0442fSSean Young if (dev->s_timeout) 49242e0442fSSean Young ret = dev->s_timeout(dev, tmp); 49342e0442fSSean Young if (!ret) 49442e0442fSSean Young dev->timeout = tmp; 49542e0442fSSean Young break; 49642e0442fSSean Young 49742e0442fSSean Young case LIRC_SET_REC_TIMEOUT_REPORTS: 49842e0442fSSean Young if (!dev->timeout) 49942e0442fSSean Young return -ENOTTY; 50042e0442fSSean Young 50142e0442fSSean Young dev->send_timeout_reports = !!val; 50242e0442fSSean Young break; 50342e0442fSSean Young 50442e0442fSSean Young default: 50542e0442fSSean Young return -ENOTTY; 50642e0442fSSean Young } 50742e0442fSSean Young 50842e0442fSSean Young if (_IOC_DIR(cmd) & _IOC_READ) 50942e0442fSSean Young ret = put_user(val, argp); 51042e0442fSSean Young 51142e0442fSSean Young return ret; 51242e0442fSSean Young } 51342e0442fSSean Young 51442e0442fSSean Young static unsigned int ir_lirc_poll(struct file *file, 51542e0442fSSean Young struct poll_table_struct *wait) 51642e0442fSSean Young { 51742e0442fSSean Young struct rc_dev *rcdev = file->private_data; 51842e0442fSSean Young unsigned int events = 0; 51942e0442fSSean Young 52042e0442fSSean Young poll_wait(file, &rcdev->wait_poll, wait); 52142e0442fSSean Young 52242e0442fSSean Young if (!rcdev->registered) { 52342e0442fSSean Young events = POLLHUP | POLLERR; 52442e0442fSSean Young } else if (rcdev->driver_type != RC_DRIVER_IR_RAW_TX) { 52542e0442fSSean Young if (rcdev->rec_mode == LIRC_MODE_SCANCODE && 52642e0442fSSean Young !kfifo_is_empty(&rcdev->scancodes)) 52742e0442fSSean Young events = POLLIN | POLLRDNORM; 52842e0442fSSean Young 52942e0442fSSean Young if (rcdev->rec_mode == LIRC_MODE_MODE2 && 53042e0442fSSean Young !kfifo_is_empty(&rcdev->rawir)) 53142e0442fSSean Young events = POLLIN | POLLRDNORM; 53242e0442fSSean Young } 53342e0442fSSean Young 53442e0442fSSean Young return events; 53542e0442fSSean Young } 53642e0442fSSean Young 53742e0442fSSean Young static ssize_t ir_lirc_read_mode2(struct file *file, char __user *buffer, 53842e0442fSSean Young size_t length) 53942e0442fSSean Young { 54042e0442fSSean Young struct rc_dev *rcdev = file->private_data; 54142e0442fSSean Young unsigned int copied; 54242e0442fSSean Young int ret; 54342e0442fSSean Young 54442e0442fSSean Young if (length < sizeof(unsigned int) || length % sizeof(unsigned int)) 54542e0442fSSean Young return -EINVAL; 54642e0442fSSean Young 54742e0442fSSean Young do { 54842e0442fSSean Young if (kfifo_is_empty(&rcdev->rawir)) { 54942e0442fSSean Young if (file->f_flags & O_NONBLOCK) 55042e0442fSSean Young return -EAGAIN; 55142e0442fSSean Young 55242e0442fSSean Young ret = wait_event_interruptible(rcdev->wait_poll, 55342e0442fSSean Young !kfifo_is_empty(&rcdev->rawir) || 55442e0442fSSean Young !rcdev->registered); 55542e0442fSSean Young if (ret) 55642e0442fSSean Young return ret; 55742e0442fSSean Young } 55842e0442fSSean Young 55942e0442fSSean Young if (!rcdev->registered) 56042e0442fSSean Young return -ENODEV; 56142e0442fSSean Young 56242e0442fSSean Young ret = mutex_lock_interruptible(&rcdev->lock); 56342e0442fSSean Young if (ret) 56442e0442fSSean Young return ret; 56542e0442fSSean Young ret = kfifo_to_user(&rcdev->rawir, buffer, length, &copied); 56642e0442fSSean Young mutex_unlock(&rcdev->lock); 56742e0442fSSean Young if (ret) 56842e0442fSSean Young return ret; 56942e0442fSSean Young } while (copied == 0); 57042e0442fSSean Young 57142e0442fSSean Young return copied; 57242e0442fSSean Young } 57342e0442fSSean Young 57442e0442fSSean Young static ssize_t ir_lirc_read_scancode(struct file *file, char __user *buffer, 57542e0442fSSean Young size_t length) 57642e0442fSSean Young { 57742e0442fSSean Young struct rc_dev *rcdev = file->private_data; 57842e0442fSSean Young unsigned int copied; 57942e0442fSSean Young int ret; 58042e0442fSSean Young 58142e0442fSSean Young if (length < sizeof(struct lirc_scancode) || 58242e0442fSSean Young length % sizeof(struct lirc_scancode)) 58342e0442fSSean Young return -EINVAL; 58442e0442fSSean Young 58542e0442fSSean Young do { 58642e0442fSSean Young if (kfifo_is_empty(&rcdev->scancodes)) { 58742e0442fSSean Young if (file->f_flags & O_NONBLOCK) 58842e0442fSSean Young return -EAGAIN; 58942e0442fSSean Young 59042e0442fSSean Young ret = wait_event_interruptible(rcdev->wait_poll, 59142e0442fSSean Young !kfifo_is_empty(&rcdev->scancodes) || 59242e0442fSSean Young !rcdev->registered); 59342e0442fSSean Young if (ret) 59442e0442fSSean Young return ret; 59542e0442fSSean Young } 59642e0442fSSean Young 59742e0442fSSean Young if (!rcdev->registered) 59842e0442fSSean Young return -ENODEV; 59942e0442fSSean Young 60042e0442fSSean Young ret = mutex_lock_interruptible(&rcdev->lock); 60142e0442fSSean Young if (ret) 60242e0442fSSean Young return ret; 60342e0442fSSean Young ret = kfifo_to_user(&rcdev->scancodes, buffer, length, &copied); 60442e0442fSSean Young mutex_unlock(&rcdev->lock); 60542e0442fSSean Young if (ret) 60642e0442fSSean Young return ret; 60742e0442fSSean Young } while (copied == 0); 60842e0442fSSean Young 60942e0442fSSean Young return copied; 61042e0442fSSean Young } 61142e0442fSSean Young 61242e0442fSSean Young static ssize_t ir_lirc_read(struct file *file, char __user *buffer, 61342e0442fSSean Young size_t length, loff_t *ppos) 61442e0442fSSean Young { 61542e0442fSSean Young struct rc_dev *rcdev = file->private_data; 61642e0442fSSean Young 61742e0442fSSean Young if (rcdev->driver_type == RC_DRIVER_IR_RAW_TX) 61842e0442fSSean Young return -EINVAL; 61942e0442fSSean Young 62042e0442fSSean Young if (!rcdev->registered) 62142e0442fSSean Young return -ENODEV; 62242e0442fSSean Young 62342e0442fSSean Young if (rcdev->rec_mode == LIRC_MODE_MODE2) 62442e0442fSSean Young return ir_lirc_read_mode2(file, buffer, length); 62542e0442fSSean Young else /* LIRC_MODE_SCANCODE */ 62642e0442fSSean Young return ir_lirc_read_scancode(file, buffer, length); 62742e0442fSSean Young } 62842e0442fSSean Young 62942e0442fSSean Young static const struct file_operations lirc_fops = { 63042e0442fSSean Young .owner = THIS_MODULE, 63142e0442fSSean Young .write = ir_lirc_transmit_ir, 63242e0442fSSean Young .unlocked_ioctl = ir_lirc_ioctl, 63342e0442fSSean Young #ifdef CONFIG_COMPAT 63442e0442fSSean Young .compat_ioctl = ir_lirc_ioctl, 63542e0442fSSean Young #endif 63642e0442fSSean Young .read = ir_lirc_read, 63742e0442fSSean Young .poll = ir_lirc_poll, 63842e0442fSSean Young .open = ir_lirc_open, 63942e0442fSSean Young .release = ir_lirc_close, 64042e0442fSSean Young .llseek = no_llseek, 64142e0442fSSean Young }; 64242e0442fSSean Young 643b15e3937SDavid Härdeman static void lirc_release_device(struct device *ld) 64432cf86f6SMauro Carvalho Chehab { 645a6ddd4feSSean Young struct rc_dev *rcdev = container_of(ld, struct rc_dev, lirc_dev); 646a607f51eSSean Young 64771695affSSean Young if (rcdev->driver_type == RC_DRIVER_IR_RAW) 64871695affSSean Young kfifo_free(&rcdev->rawir); 649de142c32SSean Young if (rcdev->driver_type != RC_DRIVER_IR_RAW_TX) 650de142c32SSean Young kfifo_free(&rcdev->scancodes); 651b15e3937SDavid Härdeman 652a6ddd4feSSean Young put_device(&rcdev->dev); 653b15e3937SDavid Härdeman } 654b15e3937SDavid Härdeman 655a6ddd4feSSean Young int ir_lirc_register(struct rc_dev *dev) 6566ecccc37SDavid Härdeman { 657a6ddd4feSSean Young int err, minor; 658b15e3937SDavid Härdeman 659a6ddd4feSSean Young device_initialize(&dev->lirc_dev); 660a6ddd4feSSean Young dev->lirc_dev.class = lirc_class; 661a6ddd4feSSean Young dev->lirc_dev.release = lirc_release_device; 662a6ddd4feSSean Young dev->send_mode = LIRC_MODE_PULSE; 663b15e3937SDavid Härdeman 66462d6f199SSean Young if (dev->driver_type == RC_DRIVER_SCANCODE) 66562d6f199SSean Young dev->rec_mode = LIRC_MODE_SCANCODE; 66662d6f199SSean Young else 667de142c32SSean Young dev->rec_mode = LIRC_MODE_MODE2; 668de142c32SSean Young 669a6ddd4feSSean Young if (dev->driver_type == RC_DRIVER_IR_RAW) { 670a6ddd4feSSean Young if (kfifo_alloc(&dev->rawir, MAX_IR_EVENT_SIZE, GFP_KERNEL)) 67171695affSSean Young return -ENOMEM; 6723381b779SDavid Härdeman } 6733381b779SDavid Härdeman 674de142c32SSean Young if (dev->driver_type != RC_DRIVER_IR_RAW_TX) { 675de142c32SSean Young if (kfifo_alloc(&dev->scancodes, 32, GFP_KERNEL)) { 676de142c32SSean Young kfifo_free(&dev->rawir); 677de142c32SSean Young return -ENOMEM; 678de142c32SSean Young } 679de142c32SSean Young } 680de142c32SSean Young 681a6ddd4feSSean Young init_waitqueue_head(&dev->wait_poll); 68271695affSSean Young 683a6ddd4feSSean Young minor = ida_simple_get(&lirc_ida, 0, RC_DEV_MAX, GFP_KERNEL); 684a6ddd4feSSean Young if (minor < 0) { 685a6ddd4feSSean Young err = minor; 686a6ddd4feSSean Young goto out_kfifo; 687a6ddd4feSSean Young } 68832cf86f6SMauro Carvalho Chehab 689a6ddd4feSSean Young dev->lirc_dev.parent = &dev->dev; 690a6ddd4feSSean Young dev->lirc_dev.devt = MKDEV(MAJOR(lirc_base_dev), minor); 691a6ddd4feSSean Young dev_set_name(&dev->lirc_dev, "lirc%d", minor); 69232cf86f6SMauro Carvalho Chehab 693a6ddd4feSSean Young cdev_init(&dev->lirc_cdev, &lirc_fops); 69432cf86f6SMauro Carvalho Chehab 695a6ddd4feSSean Young err = cdev_device_add(&dev->lirc_cdev, &dev->lirc_dev); 696a6ddd4feSSean Young if (err) 697a6ddd4feSSean Young goto out_ida; 698a6ddd4feSSean Young 699a6ddd4feSSean Young get_device(&dev->dev); 700a6ddd4feSSean Young 701a6ddd4feSSean Young dev_info(&dev->dev, "lirc_dev: driver %s registered at minor = %d", 702a6ddd4feSSean Young dev->driver_name, minor); 703a6ddd4feSSean Young 704a6ddd4feSSean Young return 0; 705a6ddd4feSSean Young 706a6ddd4feSSean Young out_ida: 70746c8f477SDavid Härdeman ida_simple_remove(&lirc_ida, minor); 708a6ddd4feSSean Young out_kfifo: 709a6ddd4feSSean Young if (dev->driver_type == RC_DRIVER_IR_RAW) 710a6ddd4feSSean Young kfifo_free(&dev->rawir); 711de142c32SSean Young if (dev->driver_type != RC_DRIVER_IR_RAW_TX) 712de142c32SSean Young kfifo_free(&dev->scancodes); 7133381b779SDavid Härdeman return err; 7143381b779SDavid Härdeman } 71532cf86f6SMauro Carvalho Chehab 716a6ddd4feSSean Young void ir_lirc_unregister(struct rc_dev *dev) 71732cf86f6SMauro Carvalho Chehab { 718a6ddd4feSSean Young dev_dbg(&dev->dev, "lirc_dev: driver %s unregistered from minor = %d\n", 719a6ddd4feSSean Young dev->driver_name, MINOR(dev->lirc_dev.devt)); 72071695affSSean Young 721a6ddd4feSSean Young mutex_lock(&dev->lock); 72232cf86f6SMauro Carvalho Chehab 723a6ddd4feSSean Young if (dev->lirc_open) { 724a6ddd4feSSean Young dev_dbg(&dev->dev, LOGHEAD "releasing opened driver\n", 725a6ddd4feSSean Young dev->driver_name, MINOR(dev->lirc_dev.devt)); 726a6ddd4feSSean Young wake_up_poll(&dev->wait_poll, POLLHUP); 72774c839b2SSean Young } 72874c839b2SSean Young 729a6ddd4feSSean Young mutex_unlock(&dev->lock); 73032cf86f6SMauro Carvalho Chehab 731a6ddd4feSSean Young cdev_device_del(&dev->lirc_cdev, &dev->lirc_dev); 732a6ddd4feSSean Young ida_simple_remove(&lirc_ida, MINOR(dev->lirc_dev.devt)); 733a6ddd4feSSean Young put_device(&dev->lirc_dev); 73432cf86f6SMauro Carvalho Chehab } 73532cf86f6SMauro Carvalho Chehab 736a60d64b1SSean Young int __init lirc_dev_init(void) 73732cf86f6SMauro Carvalho Chehab { 73832cf86f6SMauro Carvalho Chehab int retval; 73932cf86f6SMauro Carvalho Chehab 74032cf86f6SMauro Carvalho Chehab lirc_class = class_create(THIS_MODULE, "lirc"); 74132cf86f6SMauro Carvalho Chehab if (IS_ERR(lirc_class)) { 7423fac0314SAndi Shyti pr_err("class_create failed\n"); 74354fcecafSAndi Shyti return PTR_ERR(lirc_class); 74432cf86f6SMauro Carvalho Chehab } 74532cf86f6SMauro Carvalho Chehab 746a6ddd4feSSean Young retval = alloc_chrdev_region(&lirc_base_dev, 0, RC_DEV_MAX, 747463015ddSDavid Härdeman "BaseRemoteCtl"); 74832cf86f6SMauro Carvalho Chehab if (retval) { 74932cf86f6SMauro Carvalho Chehab class_destroy(lirc_class); 7503fac0314SAndi Shyti pr_err("alloc_chrdev_region failed\n"); 75154fcecafSAndi Shyti return retval; 75232cf86f6SMauro Carvalho Chehab } 75332cf86f6SMauro Carvalho Chehab 7543fac0314SAndi Shyti pr_info("IR Remote Control driver registered, major %d\n", 7553fac0314SAndi Shyti MAJOR(lirc_base_dev)); 75632cf86f6SMauro Carvalho Chehab 75754fcecafSAndi Shyti return 0; 75832cf86f6SMauro Carvalho Chehab } 75932cf86f6SMauro Carvalho Chehab 760a60d64b1SSean Young void __exit lirc_dev_exit(void) 76132cf86f6SMauro Carvalho Chehab { 76232cf86f6SMauro Carvalho Chehab class_destroy(lirc_class); 763a6ddd4feSSean Young unregister_chrdev_region(lirc_base_dev, RC_DEV_MAX); 76432cf86f6SMauro Carvalho Chehab } 765