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