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/ir-core.h> 20#include "ir-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 input_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 input_dev *input_dev, struct ir_raw_event ev) 33{ 34 struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); 35 int sample; 36 37 if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC)) 38 return 0; 39 40 if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf) 41 return -EINVAL; 42 43 if (IS_RESET(ev)) 44 return 0; 45 46 IR_dprintk(2, "LIRC data transfer started (%uus %s)\n", 47 TO_US(ev.duration), TO_STR(ev.pulse)); 48 49 sample = ev.duration / 1000; 50 if (ev.pulse) 51 sample |= PULSE_BIT; 52 53 lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf, 54 (unsigned char *) &sample); 55 wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll); 56 57 58 return 0; 59} 60 61static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf, 62 size_t n, loff_t *ppos) 63{ 64 struct lirc_codec *lirc; 65 struct ir_input_dev *ir_dev; 66 int *txbuf; /* buffer with values to transmit */ 67 int ret = 0, count; 68 69 lirc = lirc_get_pdata(file); 70 if (!lirc) 71 return -EFAULT; 72 73 if (n % sizeof(int)) 74 return -EINVAL; 75 76 count = n / sizeof(int); 77 if (count > LIRCBUF_SIZE || count % 2 == 0) 78 return -EINVAL; 79 80 txbuf = memdup_user(buf, n); 81 if (IS_ERR(txbuf)) 82 return PTR_ERR(txbuf); 83 84 ir_dev = lirc->ir_dev; 85 if (!ir_dev) { 86 ret = -EFAULT; 87 goto out; 88 } 89 90 if (ir_dev->props && ir_dev->props->tx_ir) 91 ret = ir_dev->props->tx_ir(ir_dev->props->priv, txbuf, (u32)n); 92 93out: 94 kfree(txbuf); 95 return ret; 96} 97 98static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, 99 unsigned long __user arg) 100{ 101 struct lirc_codec *lirc; 102 struct ir_input_dev *ir_dev; 103 int ret = 0; 104 void *drv_data; 105 unsigned long val = 0; 106 107 lirc = lirc_get_pdata(filep); 108 if (!lirc) 109 return -EFAULT; 110 111 ir_dev = lirc->ir_dev; 112 if (!ir_dev || !ir_dev->props || !ir_dev->props->priv) 113 return -EFAULT; 114 115 drv_data = ir_dev->props->priv; 116 117 if (_IOC_DIR(cmd) & _IOC_WRITE) { 118 ret = get_user(val, (unsigned long *)arg); 119 if (ret) 120 return ret; 121 } 122 123 switch (cmd) { 124 125 /* legacy support */ 126 case LIRC_GET_SEND_MODE: 127 val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; 128 break; 129 130 case LIRC_SET_SEND_MODE: 131 if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) 132 return -EINVAL; 133 break; 134 135 /* TX settings */ 136 case LIRC_SET_TRANSMITTER_MASK: 137 if (ir_dev->props->s_tx_mask) 138 ret = ir_dev->props->s_tx_mask(drv_data, (u32)val); 139 else 140 return -EINVAL; 141 break; 142 143 case LIRC_SET_SEND_CARRIER: 144 if (ir_dev->props->s_tx_carrier) 145 ir_dev->props->s_tx_carrier(drv_data, (u32)val); 146 else 147 return -EINVAL; 148 break; 149 150 case LIRC_SET_SEND_DUTY_CYCLE: 151 if (!ir_dev->props->s_tx_duty_cycle) 152 return -ENOSYS; 153 154 if (val <= 0 || val >= 100) 155 return -EINVAL; 156 157 ir_dev->props->s_tx_duty_cycle(ir_dev->props->priv, val); 158 break; 159 160 /* RX settings */ 161 case LIRC_SET_REC_CARRIER: 162 if (ir_dev->props->s_rx_carrier_range) 163 ret = ir_dev->props->s_rx_carrier_range( 164 ir_dev->props->priv, 165 ir_dev->raw->lirc.carrier_low, val); 166 else 167 return -ENOSYS; 168 169 if (!ret) 170 ir_dev->raw->lirc.carrier_low = 0; 171 break; 172 173 case LIRC_SET_REC_CARRIER_RANGE: 174 if (val >= 0) 175 ir_dev->raw->lirc.carrier_low = val; 176 break; 177 178 179 case LIRC_GET_REC_RESOLUTION: 180 val = ir_dev->props->rx_resolution; 181 break; 182 183 case LIRC_SET_WIDEBAND_RECEIVER: 184 if (ir_dev->props->s_learning_mode) 185 return ir_dev->props->s_learning_mode( 186 ir_dev->props->priv, !!val); 187 else 188 return -ENOSYS; 189 190 /* Generic timeout support */ 191 case LIRC_GET_MIN_TIMEOUT: 192 if (!ir_dev->props->max_timeout) 193 return -ENOSYS; 194 val = ir_dev->props->min_timeout / 1000; 195 break; 196 197 case LIRC_GET_MAX_TIMEOUT: 198 if (!ir_dev->props->max_timeout) 199 return -ENOSYS; 200 val = ir_dev->props->max_timeout / 1000; 201 break; 202 203 case LIRC_SET_REC_TIMEOUT: 204 if (val < ir_dev->props->min_timeout || 205 val > ir_dev->props->max_timeout) 206 return -EINVAL; 207 ir_dev->props->timeout = val * 1000; 208 break; 209 210 default: 211 return lirc_dev_fop_ioctl(filep, cmd, arg); 212 } 213 214 if (_IOC_DIR(cmd) & _IOC_READ) 215 ret = put_user(val, (unsigned long *)arg); 216 217 return ret; 218} 219 220static int ir_lirc_open(void *data) 221{ 222 return 0; 223} 224 225static void ir_lirc_close(void *data) 226{ 227 return; 228} 229 230static struct file_operations lirc_fops = { 231 .owner = THIS_MODULE, 232 .write = ir_lirc_transmit_ir, 233 .unlocked_ioctl = ir_lirc_ioctl, 234 .read = lirc_dev_fop_read, 235 .poll = lirc_dev_fop_poll, 236 .open = lirc_dev_fop_open, 237 .release = lirc_dev_fop_close, 238}; 239 240static int ir_lirc_register(struct input_dev *input_dev) 241{ 242 struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); 243 struct lirc_driver *drv; 244 struct lirc_buffer *rbuf; 245 int rc = -ENOMEM; 246 unsigned long features; 247 248 drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); 249 if (!drv) 250 return rc; 251 252 rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); 253 if (!rbuf) 254 goto rbuf_alloc_failed; 255 256 rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE); 257 if (rc) 258 goto rbuf_init_failed; 259 260 features = LIRC_CAN_REC_MODE2; 261 if (ir_dev->props->tx_ir) { 262 263 features |= LIRC_CAN_SEND_PULSE; 264 if (ir_dev->props->s_tx_mask) 265 features |= LIRC_CAN_SET_TRANSMITTER_MASK; 266 if (ir_dev->props->s_tx_carrier) 267 features |= LIRC_CAN_SET_SEND_CARRIER; 268 269 if (ir_dev->props->s_tx_duty_cycle) 270 features |= LIRC_CAN_SET_SEND_DUTY_CYCLE; 271 } 272 273 if (ir_dev->props->s_rx_carrier_range) 274 features |= LIRC_CAN_SET_REC_CARRIER | 275 LIRC_CAN_SET_REC_CARRIER_RANGE; 276 277 if (ir_dev->props->s_learning_mode) 278 features |= LIRC_CAN_USE_WIDEBAND_RECEIVER; 279 280 if (ir_dev->props->max_timeout) 281 features |= LIRC_CAN_SET_REC_TIMEOUT; 282 283 284 snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)", 285 ir_dev->driver_name); 286 drv->minor = -1; 287 drv->features = features; 288 drv->data = &ir_dev->raw->lirc; 289 drv->rbuf = rbuf; 290 drv->set_use_inc = &ir_lirc_open; 291 drv->set_use_dec = &ir_lirc_close; 292 drv->code_length = sizeof(struct ir_raw_event) * 8; 293 drv->fops = &lirc_fops; 294 drv->dev = &ir_dev->dev; 295 drv->owner = THIS_MODULE; 296 297 drv->minor = lirc_register_driver(drv); 298 if (drv->minor < 0) { 299 rc = -ENODEV; 300 goto lirc_register_failed; 301 } 302 303 ir_dev->raw->lirc.drv = drv; 304 ir_dev->raw->lirc.ir_dev = ir_dev; 305 return 0; 306 307lirc_register_failed: 308rbuf_init_failed: 309 kfree(rbuf); 310rbuf_alloc_failed: 311 kfree(drv); 312 313 return rc; 314} 315 316static int ir_lirc_unregister(struct input_dev *input_dev) 317{ 318 struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); 319 struct lirc_codec *lirc = &ir_dev->raw->lirc; 320 321 lirc_unregister_driver(lirc->drv->minor); 322 lirc_buffer_free(lirc->drv->rbuf); 323 kfree(lirc->drv); 324 325 return 0; 326} 327 328static struct ir_raw_handler lirc_handler = { 329 .protocols = IR_TYPE_LIRC, 330 .decode = ir_lirc_decode, 331 .raw_register = ir_lirc_register, 332 .raw_unregister = ir_lirc_unregister, 333}; 334 335static int __init ir_lirc_codec_init(void) 336{ 337 ir_raw_handler_register(&lirc_handler); 338 339 printk(KERN_INFO "IR LIRC bridge handler initialized\n"); 340 return 0; 341} 342 343static void __exit ir_lirc_codec_exit(void) 344{ 345 ir_raw_handler_unregister(&lirc_handler); 346} 347 348module_init(ir_lirc_codec_init); 349module_exit(ir_lirc_codec_exit); 350 351MODULE_LICENSE("GPL"); 352MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); 353MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); 354MODULE_DESCRIPTION("LIRC IR handler bridge"); 355