Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.9-rc2 436 lines 9.5 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 (!(dev->raw->enabled_protocols & 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 ret = dev->tx_ir(dev, txbuf, count); 144 if (ret < 0) 145 goto out; 146 147 for (i = 0; i < ret; i++) 148 duration += txbuf[i]; 149 150 ret *= sizeof(unsigned int); 151 152 /* 153 * The lircd gap calculation expects the write function to 154 * wait for the actual IR signal to be transmitted before 155 * returning. 156 */ 157 towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get()); 158 if (towait > 0) { 159 set_current_state(TASK_INTERRUPTIBLE); 160 schedule_timeout(usecs_to_jiffies(towait)); 161 } 162 163out: 164 kfree(txbuf); 165 return ret; 166} 167 168static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, 169 unsigned long arg) 170{ 171 struct lirc_codec *lirc; 172 struct rc_dev *dev; 173 u32 __user *argp = (u32 __user *)(arg); 174 int ret = 0; 175 __u32 val = 0, tmp; 176 177 lirc = lirc_get_pdata(filep); 178 if (!lirc) 179 return -EFAULT; 180 181 dev = lirc->dev; 182 if (!dev) 183 return -EFAULT; 184 185 if (_IOC_DIR(cmd) & _IOC_WRITE) { 186 ret = get_user(val, argp); 187 if (ret) 188 return ret; 189 } 190 191 switch (cmd) { 192 193 /* legacy support */ 194 case LIRC_GET_SEND_MODE: 195 val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; 196 break; 197 198 case LIRC_SET_SEND_MODE: 199 if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) 200 return -EINVAL; 201 return 0; 202 203 /* TX settings */ 204 case LIRC_SET_TRANSMITTER_MASK: 205 if (!dev->s_tx_mask) 206 return -ENOSYS; 207 208 return dev->s_tx_mask(dev, val); 209 210 case LIRC_SET_SEND_CARRIER: 211 if (!dev->s_tx_carrier) 212 return -ENOSYS; 213 214 return dev->s_tx_carrier(dev, val); 215 216 case LIRC_SET_SEND_DUTY_CYCLE: 217 if (!dev->s_tx_duty_cycle) 218 return -ENOSYS; 219 220 if (val <= 0 || val >= 100) 221 return -EINVAL; 222 223 return dev->s_tx_duty_cycle(dev, val); 224 225 /* RX settings */ 226 case LIRC_SET_REC_CARRIER: 227 if (!dev->s_rx_carrier_range) 228 return -ENOSYS; 229 230 if (val <= 0) 231 return -EINVAL; 232 233 return dev->s_rx_carrier_range(dev, 234 dev->raw->lirc.carrier_low, 235 val); 236 237 case LIRC_SET_REC_CARRIER_RANGE: 238 if (val <= 0) 239 return -EINVAL; 240 241 dev->raw->lirc.carrier_low = val; 242 return 0; 243 244 case LIRC_GET_REC_RESOLUTION: 245 val = dev->rx_resolution; 246 break; 247 248 case LIRC_SET_WIDEBAND_RECEIVER: 249 if (!dev->s_learning_mode) 250 return -ENOSYS; 251 252 return dev->s_learning_mode(dev, !!val); 253 254 case LIRC_SET_MEASURE_CARRIER_MODE: 255 if (!dev->s_carrier_report) 256 return -ENOSYS; 257 258 return dev->s_carrier_report(dev, !!val); 259 260 /* Generic timeout support */ 261 case LIRC_GET_MIN_TIMEOUT: 262 if (!dev->max_timeout) 263 return -ENOSYS; 264 val = dev->min_timeout / 1000; 265 break; 266 267 case LIRC_GET_MAX_TIMEOUT: 268 if (!dev->max_timeout) 269 return -ENOSYS; 270 val = dev->max_timeout / 1000; 271 break; 272 273 case LIRC_SET_REC_TIMEOUT: 274 if (!dev->max_timeout) 275 return -ENOSYS; 276 277 tmp = val * 1000; 278 279 if (tmp < dev->min_timeout || 280 tmp > dev->max_timeout) 281 return -EINVAL; 282 283 dev->timeout = tmp; 284 break; 285 286 case LIRC_SET_REC_TIMEOUT_REPORTS: 287 lirc->send_timeout_reports = !!val; 288 break; 289 290 default: 291 return lirc_dev_fop_ioctl(filep, cmd, arg); 292 } 293 294 if (_IOC_DIR(cmd) & _IOC_READ) 295 ret = put_user(val, argp); 296 297 return ret; 298} 299 300static int ir_lirc_open(void *data) 301{ 302 return 0; 303} 304 305static void ir_lirc_close(void *data) 306{ 307 return; 308} 309 310static struct file_operations lirc_fops = { 311 .owner = THIS_MODULE, 312 .write = ir_lirc_transmit_ir, 313 .unlocked_ioctl = ir_lirc_ioctl, 314#ifdef CONFIG_COMPAT 315 .compat_ioctl = ir_lirc_ioctl, 316#endif 317 .read = lirc_dev_fop_read, 318 .poll = lirc_dev_fop_poll, 319 .open = lirc_dev_fop_open, 320 .release = lirc_dev_fop_close, 321 .llseek = no_llseek, 322}; 323 324static int ir_lirc_register(struct rc_dev *dev) 325{ 326 struct lirc_driver *drv; 327 struct lirc_buffer *rbuf; 328 int rc = -ENOMEM; 329 unsigned long features; 330 331 drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); 332 if (!drv) 333 return rc; 334 335 rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); 336 if (!rbuf) 337 goto rbuf_alloc_failed; 338 339 rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE); 340 if (rc) 341 goto rbuf_init_failed; 342 343 features = LIRC_CAN_REC_MODE2; 344 if (dev->tx_ir) { 345 features |= LIRC_CAN_SEND_PULSE; 346 if (dev->s_tx_mask) 347 features |= LIRC_CAN_SET_TRANSMITTER_MASK; 348 if (dev->s_tx_carrier) 349 features |= LIRC_CAN_SET_SEND_CARRIER; 350 if (dev->s_tx_duty_cycle) 351 features |= LIRC_CAN_SET_SEND_DUTY_CYCLE; 352 } 353 354 if (dev->s_rx_carrier_range) 355 features |= LIRC_CAN_SET_REC_CARRIER | 356 LIRC_CAN_SET_REC_CARRIER_RANGE; 357 358 if (dev->s_learning_mode) 359 features |= LIRC_CAN_USE_WIDEBAND_RECEIVER; 360 361 if (dev->s_carrier_report) 362 features |= LIRC_CAN_MEASURE_CARRIER; 363 364 if (dev->max_timeout) 365 features |= LIRC_CAN_SET_REC_TIMEOUT; 366 367 snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)", 368 dev->driver_name); 369 drv->minor = -1; 370 drv->features = features; 371 drv->data = &dev->raw->lirc; 372 drv->rbuf = rbuf; 373 drv->set_use_inc = &ir_lirc_open; 374 drv->set_use_dec = &ir_lirc_close; 375 drv->code_length = sizeof(struct ir_raw_event) * 8; 376 drv->fops = &lirc_fops; 377 drv->dev = &dev->dev; 378 drv->owner = THIS_MODULE; 379 380 drv->minor = lirc_register_driver(drv); 381 if (drv->minor < 0) { 382 rc = -ENODEV; 383 goto lirc_register_failed; 384 } 385 386 dev->raw->lirc.drv = drv; 387 dev->raw->lirc.dev = dev; 388 return 0; 389 390lirc_register_failed: 391rbuf_init_failed: 392 kfree(rbuf); 393rbuf_alloc_failed: 394 kfree(drv); 395 396 return rc; 397} 398 399static int ir_lirc_unregister(struct rc_dev *dev) 400{ 401 struct lirc_codec *lirc = &dev->raw->lirc; 402 403 lirc_unregister_driver(lirc->drv->minor); 404 lirc_buffer_free(lirc->drv->rbuf); 405 kfree(lirc->drv); 406 407 return 0; 408} 409 410static struct ir_raw_handler lirc_handler = { 411 .protocols = RC_BIT_LIRC, 412 .decode = ir_lirc_decode, 413 .raw_register = ir_lirc_register, 414 .raw_unregister = ir_lirc_unregister, 415}; 416 417static int __init ir_lirc_codec_init(void) 418{ 419 ir_raw_handler_register(&lirc_handler); 420 421 printk(KERN_INFO "IR LIRC bridge handler initialized\n"); 422 return 0; 423} 424 425static void __exit ir_lirc_codec_exit(void) 426{ 427 ir_raw_handler_unregister(&lirc_handler); 428} 429 430module_init(ir_lirc_codec_init); 431module_exit(ir_lirc_codec_exit); 432 433MODULE_LICENSE("GPL"); 434MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); 435MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); 436MODULE_DESCRIPTION("LIRC IR handler bridge");