linux/drivers/media/rc/ir-lirc-codec.c
<<
>>
Prefs
   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");
 412