ir-lirc-codec.c revision 52b661449aecc47e652a164c0d8078b31e10aca0
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, count; 104 105 lirc = lirc_get_pdata(file); 106 if (!lirc) 107 return -EFAULT; 108 109 if (n % sizeof(int)) 110 return -EINVAL; 111 112 count = n / sizeof(int); 113 if (count > LIRCBUF_SIZE || count % 2 == 0) 114 return -EINVAL; 115 116 txbuf = memdup_user(buf, n); 117 if (IS_ERR(txbuf)) 118 return PTR_ERR(txbuf); 119 120 dev = lirc->dev; 121 if (!dev) { 122 ret = -EFAULT; 123 goto out; 124 } 125 126 if (dev->tx_ir) 127 ret = dev->tx_ir(dev, txbuf, (u32)n); 128 129out: 130 kfree(txbuf); 131 return ret; 132} 133 134static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, 135 unsigned long __user arg) 136{ 137 struct lirc_codec *lirc; 138 struct rc_dev *dev; 139 int ret = 0; 140 __u32 val = 0, tmp; 141 142 lirc = lirc_get_pdata(filep); 143 if (!lirc) 144 return -EFAULT; 145 146 dev = lirc->dev; 147 if (!dev) 148 return -EFAULT; 149 150 if (_IOC_DIR(cmd) & _IOC_WRITE) { 151 ret = get_user(val, (__u32 *)arg); 152 if (ret) 153 return ret; 154 } 155 156 switch (cmd) { 157 158 /* legacy support */ 159 case LIRC_GET_SEND_MODE: 160 val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; 161 break; 162 163 case LIRC_SET_SEND_MODE: 164 if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) 165 return -EINVAL; 166 return 0; 167 168 /* TX settings */ 169 case LIRC_SET_TRANSMITTER_MASK: 170 if (!dev->s_tx_mask) 171 return -EINVAL; 172 173 return dev->s_tx_mask(dev, val); 174 175 case LIRC_SET_SEND_CARRIER: 176 if (!dev->s_tx_carrier) 177 return -EINVAL; 178 179 return dev->s_tx_carrier(dev, val); 180 181 case LIRC_SET_SEND_DUTY_CYCLE: 182 if (!dev->s_tx_duty_cycle) 183 return -ENOSYS; 184 185 if (val <= 0 || val >= 100) 186 return -EINVAL; 187 188 return dev->s_tx_duty_cycle(dev, val); 189 190 /* RX settings */ 191 case LIRC_SET_REC_CARRIER: 192 if (!dev->s_rx_carrier_range) 193 return -ENOSYS; 194 195 if (val <= 0) 196 return -EINVAL; 197 198 return dev->s_rx_carrier_range(dev, 199 dev->raw->lirc.carrier_low, 200 val); 201 202 case LIRC_SET_REC_CARRIER_RANGE: 203 if (val <= 0) 204 return -EINVAL; 205 206 dev->raw->lirc.carrier_low = val; 207 return 0; 208 209 case LIRC_GET_REC_RESOLUTION: 210 val = dev->rx_resolution; 211 break; 212 213 case LIRC_SET_WIDEBAND_RECEIVER: 214 if (!dev->s_learning_mode) 215 return -ENOSYS; 216 217 return dev->s_learning_mode(dev, !!val); 218 219 case LIRC_SET_MEASURE_CARRIER_MODE: 220 if (!dev->s_carrier_report) 221 return -ENOSYS; 222 223 return dev->s_carrier_report(dev, !!val); 224 225 /* Generic timeout support */ 226 case LIRC_GET_MIN_TIMEOUT: 227 if (!dev->max_timeout) 228 return -ENOSYS; 229 val = dev->min_timeout / 1000; 230 break; 231 232 case LIRC_GET_MAX_TIMEOUT: 233 if (!dev->max_timeout) 234 return -ENOSYS; 235 val = dev->max_timeout / 1000; 236 break; 237 238 case LIRC_SET_REC_TIMEOUT: 239 if (!dev->max_timeout) 240 return -ENOSYS; 241 242 tmp = val * 1000; 243 244 if (tmp < dev->min_timeout || 245 tmp > dev->max_timeout) 246 return -EINVAL; 247 248 dev->timeout = tmp; 249 break; 250 251 case LIRC_SET_REC_TIMEOUT_REPORTS: 252 lirc->send_timeout_reports = !!val; 253 break; 254 255 default: 256 return lirc_dev_fop_ioctl(filep, cmd, arg); 257 } 258 259 if (_IOC_DIR(cmd) & _IOC_READ) 260 ret = put_user(val, (__u32 *)arg); 261 262 return ret; 263} 264 265static int ir_lirc_open(void *data) 266{ 267 return 0; 268} 269 270static void ir_lirc_close(void *data) 271{ 272 return; 273} 274 275static struct file_operations lirc_fops = { 276 .owner = THIS_MODULE, 277 .write = ir_lirc_transmit_ir, 278 .unlocked_ioctl = ir_lirc_ioctl, 279#ifdef CONFIG_COMPAT 280 .compat_ioctl = ir_lirc_ioctl, 281#endif 282 .read = lirc_dev_fop_read, 283 .poll = lirc_dev_fop_poll, 284 .open = lirc_dev_fop_open, 285 .release = lirc_dev_fop_close, 286 .llseek = no_llseek, 287}; 288 289static int ir_lirc_register(struct rc_dev *dev) 290{ 291 struct lirc_driver *drv; 292 struct lirc_buffer *rbuf; 293 int rc = -ENOMEM; 294 unsigned long features; 295 296 drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); 297 if (!drv) 298 return rc; 299 300 rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); 301 if (!rbuf) 302 goto rbuf_alloc_failed; 303 304 rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE); 305 if (rc) 306 goto rbuf_init_failed; 307 308 features = LIRC_CAN_REC_MODE2; 309 if (dev->tx_ir) { 310 features |= LIRC_CAN_SEND_PULSE; 311 if (dev->s_tx_mask) 312 features |= LIRC_CAN_SET_TRANSMITTER_MASK; 313 if (dev->s_tx_carrier) 314 features |= LIRC_CAN_SET_SEND_CARRIER; 315 if (dev->s_tx_duty_cycle) 316 features |= LIRC_CAN_SET_SEND_DUTY_CYCLE; 317 } 318 319 if (dev->s_rx_carrier_range) 320 features |= LIRC_CAN_SET_REC_CARRIER | 321 LIRC_CAN_SET_REC_CARRIER_RANGE; 322 323 if (dev->s_learning_mode) 324 features |= LIRC_CAN_USE_WIDEBAND_RECEIVER; 325 326 if (dev->s_carrier_report) 327 features |= LIRC_CAN_MEASURE_CARRIER; 328 329 if (dev->max_timeout) 330 features |= LIRC_CAN_SET_REC_TIMEOUT; 331 332 snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)", 333 dev->driver_name); 334 drv->minor = -1; 335 drv->features = features; 336 drv->data = &dev->raw->lirc; 337 drv->rbuf = rbuf; 338 drv->set_use_inc = &ir_lirc_open; 339 drv->set_use_dec = &ir_lirc_close; 340 drv->code_length = sizeof(struct ir_raw_event) * 8; 341 drv->fops = &lirc_fops; 342 drv->dev = &dev->dev; 343 drv->owner = THIS_MODULE; 344 345 drv->minor = lirc_register_driver(drv); 346 if (drv->minor < 0) { 347 rc = -ENODEV; 348 goto lirc_register_failed; 349 } 350 351 dev->raw->lirc.drv = drv; 352 dev->raw->lirc.dev = dev; 353 return 0; 354 355lirc_register_failed: 356rbuf_init_failed: 357 kfree(rbuf); 358rbuf_alloc_failed: 359 kfree(drv); 360 361 return rc; 362} 363 364static int ir_lirc_unregister(struct rc_dev *dev) 365{ 366 struct lirc_codec *lirc = &dev->raw->lirc; 367 368 lirc_unregister_driver(lirc->drv->minor); 369 lirc_buffer_free(lirc->drv->rbuf); 370 kfree(lirc->drv); 371 372 return 0; 373} 374 375static struct ir_raw_handler lirc_handler = { 376 .protocols = RC_TYPE_LIRC, 377 .decode = ir_lirc_decode, 378 .raw_register = ir_lirc_register, 379 .raw_unregister = ir_lirc_unregister, 380}; 381 382static int __init ir_lirc_codec_init(void) 383{ 384 ir_raw_handler_register(&lirc_handler); 385 386 printk(KERN_INFO "IR LIRC bridge handler initialized\n"); 387 return 0; 388} 389 390static void __exit ir_lirc_codec_exit(void) 391{ 392 ir_raw_handler_unregister(&lirc_handler); 393} 394 395module_init(ir_lirc_codec_init); 396module_exit(ir_lirc_codec_exit); 397 398MODULE_LICENSE("GPL"); 399MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); 400MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); 401MODULE_DESCRIPTION("LIRC IR handler bridge"); 402