at v3.16 446 lines 9.7 kB view raw
1/* ir-lirc-codec.c - rc-core to classic lirc interface bridge 2 * 3 * Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation version 2 of the License. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 15#include <linux/sched.h> 16#include <linux/wait.h> 17#include <linux/module.h> 18#include <media/lirc.h> 19#include <media/lirc_dev.h> 20#include <media/rc-core.h> 21#include "rc-core-priv.h" 22 23#define LIRCBUF_SIZE 256 24 25/** 26 * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the 27 * lircd userspace daemon for decoding. 28 * @input_dev: the struct rc_dev descriptor of the device 29 * @duration: the struct ir_raw_event descriptor of the pulse/space 30 * 31 * This function returns -EINVAL if the lirc interfaces aren't wired up. 32 */ 33static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) 34{ 35 struct lirc_codec *lirc = &dev->raw->lirc; 36 int sample; 37 38 if (!rc_protocols_enabled(dev, RC_BIT_LIRC)) 39 return 0; 40 41 if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf) 42 return -EINVAL; 43 44 /* Packet start */ 45 if (ev.reset) 46 return 0; 47 48 /* Carrier reports */ 49 if (ev.carrier_report) { 50 sample = LIRC_FREQUENCY(ev.carrier); 51 IR_dprintk(2, "carrier report (freq: %d)\n", sample); 52 53 /* Packet end */ 54 } else if (ev.timeout) { 55 56 if (lirc->gap) 57 return 0; 58 59 lirc->gap_start = ktime_get(); 60 lirc->gap = true; 61 lirc->gap_duration = ev.duration; 62 63 if (!lirc->send_timeout_reports) 64 return 0; 65 66 sample = LIRC_TIMEOUT(ev.duration / 1000); 67 IR_dprintk(2, "timeout report (duration: %d)\n", sample); 68 69 /* Normal sample */ 70 } else { 71 72 if (lirc->gap) { 73 int gap_sample; 74 75 lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(), 76 lirc->gap_start)); 77 78 /* Convert to ms and cap by LIRC_VALUE_MASK */ 79 do_div(lirc->gap_duration, 1000); 80 lirc->gap_duration = min(lirc->gap_duration, 81 (u64)LIRC_VALUE_MASK); 82 83 gap_sample = LIRC_SPACE(lirc->gap_duration); 84 lirc_buffer_write(dev->raw->lirc.drv->rbuf, 85 (unsigned char *) &gap_sample); 86 lirc->gap = false; 87 } 88 89 sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) : 90 LIRC_SPACE(ev.duration / 1000); 91 IR_dprintk(2, "delivering %uus %s to lirc_dev\n", 92 TO_US(ev.duration), TO_STR(ev.pulse)); 93 } 94 95 lirc_buffer_write(dev->raw->lirc.drv->rbuf, 96 (unsigned char *) &sample); 97 wake_up(&dev->raw->lirc.drv->rbuf->wait_poll); 98 99 return 0; 100} 101 102static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, 103 size_t n, loff_t *ppos) 104{ 105 struct lirc_codec *lirc; 106 struct rc_dev *dev; 107 unsigned int *txbuf; /* buffer with values to transmit */ 108 ssize_t ret = -EINVAL; 109 size_t count; 110 ktime_t start; 111 s64 towait; 112 unsigned int duration = 0; /* signal duration in us */ 113 int i; 114 115 start = ktime_get(); 116 117 lirc = lirc_get_pdata(file); 118 if (!lirc) 119 return -EFAULT; 120 121 if (n < sizeof(unsigned) || n % sizeof(unsigned)) 122 return -EINVAL; 123 124 count = n / sizeof(unsigned); 125 if (count > LIRCBUF_SIZE || count % 2 == 0) 126 return -EINVAL; 127 128 txbuf = memdup_user(buf, n); 129 if (IS_ERR(txbuf)) 130 return PTR_ERR(txbuf); 131 132 dev = lirc->dev; 133 if (!dev) { 134 ret = -EFAULT; 135 goto out; 136 } 137 138 if (!dev->tx_ir) { 139 ret = -ENOSYS; 140 goto out; 141 } 142 143 for (i = 0; i < count; i++) { 144 if (txbuf[i] > IR_MAX_DURATION / 1000 - duration || !txbuf[i]) { 145 ret = -EINVAL; 146 goto out; 147 } 148 149 duration += txbuf[i]; 150 } 151 152 ret = dev->tx_ir(dev, txbuf, count); 153 if (ret < 0) 154 goto out; 155 156 for (duration = i = 0; i < ret; i++) 157 duration += txbuf[i]; 158 159 ret *= sizeof(unsigned int); 160 161 /* 162 * The lircd gap calculation expects the write function to 163 * wait for the actual IR signal to be transmitted before 164 * returning. 165 */ 166 towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get()); 167 if (towait > 0) { 168 set_current_state(TASK_INTERRUPTIBLE); 169 schedule_timeout(usecs_to_jiffies(towait)); 170 } 171 172out: 173 kfree(txbuf); 174 return ret; 175} 176 177static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, 178 unsigned long arg) 179{ 180 struct lirc_codec *lirc; 181 struct rc_dev *dev; 182 u32 __user *argp = (u32 __user *)(arg); 183 int ret = 0; 184 __u32 val = 0, tmp; 185 186 lirc = lirc_get_pdata(filep); 187 if (!lirc) 188 return -EFAULT; 189 190 dev = lirc->dev; 191 if (!dev) 192 return -EFAULT; 193 194 if (_IOC_DIR(cmd) & _IOC_WRITE) { 195 ret = get_user(val, argp); 196 if (ret) 197 return ret; 198 } 199 200 switch (cmd) { 201 202 /* legacy support */ 203 case LIRC_GET_SEND_MODE: 204 val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; 205 break; 206 207 case LIRC_SET_SEND_MODE: 208 if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) 209 return -EINVAL; 210 return 0; 211 212 /* TX settings */ 213 case LIRC_SET_TRANSMITTER_MASK: 214 if (!dev->s_tx_mask) 215 return -ENOSYS; 216 217 return dev->s_tx_mask(dev, val); 218 219 case LIRC_SET_SEND_CARRIER: 220 if (!dev->s_tx_carrier) 221 return -ENOSYS; 222 223 return dev->s_tx_carrier(dev, val); 224 225 case LIRC_SET_SEND_DUTY_CYCLE: 226 if (!dev->s_tx_duty_cycle) 227 return -ENOSYS; 228 229 if (val <= 0 || val >= 100) 230 return -EINVAL; 231 232 return dev->s_tx_duty_cycle(dev, val); 233 234 /* RX settings */ 235 case LIRC_SET_REC_CARRIER: 236 if (!dev->s_rx_carrier_range) 237 return -ENOSYS; 238 239 if (val <= 0) 240 return -EINVAL; 241 242 return dev->s_rx_carrier_range(dev, 243 dev->raw->lirc.carrier_low, 244 val); 245 246 case LIRC_SET_REC_CARRIER_RANGE: 247 if (val <= 0) 248 return -EINVAL; 249 250 dev->raw->lirc.carrier_low = val; 251 return 0; 252 253 case LIRC_GET_REC_RESOLUTION: 254 val = dev->rx_resolution; 255 break; 256 257 case LIRC_SET_WIDEBAND_RECEIVER: 258 if (!dev->s_learning_mode) 259 return -ENOSYS; 260 261 return dev->s_learning_mode(dev, !!val); 262 263 case LIRC_SET_MEASURE_CARRIER_MODE: 264 if (!dev->s_carrier_report) 265 return -ENOSYS; 266 267 return dev->s_carrier_report(dev, !!val); 268 269 /* Generic timeout support */ 270 case LIRC_GET_MIN_TIMEOUT: 271 if (!dev->max_timeout) 272 return -ENOSYS; 273 val = dev->min_timeout / 1000; 274 break; 275 276 case LIRC_GET_MAX_TIMEOUT: 277 if (!dev->max_timeout) 278 return -ENOSYS; 279 val = dev->max_timeout / 1000; 280 break; 281 282 case LIRC_SET_REC_TIMEOUT: 283 if (!dev->max_timeout) 284 return -ENOSYS; 285 286 tmp = val * 1000; 287 288 if (tmp < dev->min_timeout || 289 tmp > dev->max_timeout) 290 return -EINVAL; 291 292 dev->timeout = tmp; 293 break; 294 295 case LIRC_SET_REC_TIMEOUT_REPORTS: 296 lirc->send_timeout_reports = !!val; 297 break; 298 299 default: 300 return lirc_dev_fop_ioctl(filep, cmd, arg); 301 } 302 303 if (_IOC_DIR(cmd) & _IOC_READ) 304 ret = put_user(val, argp); 305 306 return ret; 307} 308 309static int ir_lirc_open(void *data) 310{ 311 return 0; 312} 313 314static void ir_lirc_close(void *data) 315{ 316 return; 317} 318 319static const struct file_operations lirc_fops = { 320 .owner = THIS_MODULE, 321 .write = ir_lirc_transmit_ir, 322 .unlocked_ioctl = ir_lirc_ioctl, 323#ifdef CONFIG_COMPAT 324 .compat_ioctl = ir_lirc_ioctl, 325#endif 326 .read = lirc_dev_fop_read, 327 .poll = lirc_dev_fop_poll, 328 .open = lirc_dev_fop_open, 329 .release = lirc_dev_fop_close, 330 .llseek = no_llseek, 331}; 332 333static int ir_lirc_register(struct rc_dev *dev) 334{ 335 struct lirc_driver *drv; 336 struct lirc_buffer *rbuf; 337 int rc = -ENOMEM; 338 unsigned long features; 339 340 drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); 341 if (!drv) 342 return rc; 343 344 rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); 345 if (!rbuf) 346 goto rbuf_alloc_failed; 347 348 rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE); 349 if (rc) 350 goto rbuf_init_failed; 351 352 features = LIRC_CAN_REC_MODE2; 353 if (dev->tx_ir) { 354 features |= LIRC_CAN_SEND_PULSE; 355 if (dev->s_tx_mask) 356 features |= LIRC_CAN_SET_TRANSMITTER_MASK; 357 if (dev->s_tx_carrier) 358 features |= LIRC_CAN_SET_SEND_CARRIER; 359 if (dev->s_tx_duty_cycle) 360 features |= LIRC_CAN_SET_SEND_DUTY_CYCLE; 361 } 362 363 if (dev->s_rx_carrier_range) 364 features |= LIRC_CAN_SET_REC_CARRIER | 365 LIRC_CAN_SET_REC_CARRIER_RANGE; 366 367 if (dev->s_learning_mode) 368 features |= LIRC_CAN_USE_WIDEBAND_RECEIVER; 369 370 if (dev->s_carrier_report) 371 features |= LIRC_CAN_MEASURE_CARRIER; 372 373 if (dev->max_timeout) 374 features |= LIRC_CAN_SET_REC_TIMEOUT; 375 376 snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)", 377 dev->driver_name); 378 drv->minor = -1; 379 drv->features = features; 380 drv->data = &dev->raw->lirc; 381 drv->rbuf = rbuf; 382 drv->set_use_inc = &ir_lirc_open; 383 drv->set_use_dec = &ir_lirc_close; 384 drv->code_length = sizeof(struct ir_raw_event) * 8; 385 drv->fops = &lirc_fops; 386 drv->dev = &dev->dev; 387 drv->rdev = dev; 388 drv->owner = THIS_MODULE; 389 390 drv->minor = lirc_register_driver(drv); 391 if (drv->minor < 0) { 392 rc = -ENODEV; 393 goto lirc_register_failed; 394 } 395 396 dev->raw->lirc.drv = drv; 397 dev->raw->lirc.dev = dev; 398 return 0; 399 400lirc_register_failed: 401rbuf_init_failed: 402 kfree(rbuf); 403rbuf_alloc_failed: 404 kfree(drv); 405 406 return rc; 407} 408 409static int ir_lirc_unregister(struct rc_dev *dev) 410{ 411 struct lirc_codec *lirc = &dev->raw->lirc; 412 413 lirc_unregister_driver(lirc->drv->minor); 414 lirc_buffer_free(lirc->drv->rbuf); 415 kfree(lirc->drv); 416 417 return 0; 418} 419 420static struct ir_raw_handler lirc_handler = { 421 .protocols = RC_BIT_LIRC, 422 .decode = ir_lirc_decode, 423 .raw_register = ir_lirc_register, 424 .raw_unregister = ir_lirc_unregister, 425}; 426 427static int __init ir_lirc_codec_init(void) 428{ 429 ir_raw_handler_register(&lirc_handler); 430 431 printk(KERN_INFO "IR LIRC bridge handler initialized\n"); 432 return 0; 433} 434 435static void __exit ir_lirc_codec_exit(void) 436{ 437 ir_raw_handler_unregister(&lirc_handler); 438} 439 440module_init(ir_lirc_codec_init); 441module_exit(ir_lirc_codec_exit); 442 443MODULE_LICENSE("GPL"); 444MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); 445MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); 446MODULE_DESCRIPTION("LIRC IR handler bridge");