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