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