linux/drivers/media/rc/igorplugusb.c
<<
>>
Prefs
   1/*
   2 * IgorPlug-USB IR Receiver
   3 *
   4 * Copyright (C) 2014 Sean Young <sean@mess.org>
   5 *
   6 * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware.
   7 * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm
   8 *
   9 * Based on the lirc_igorplugusb.c driver:
  10 *      Copyright (C) 2004 Jan M. Hochstein
  11 *      <hochstein@algo.informatik.tu-darmstadt.de>
  12 *
  13 * This program is free software; you can redistribute it and/or modify
  14 * it under the terms of the GNU General Public License as published by
  15 * the Free Software Foundation; either version 2 of the License, or
  16 * (at your option) any later version.
  17 *
  18 * This program is distributed in the hope that it will be useful,
  19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21 * GNU General Public License for more details.
  22 */
  23#include <linux/device.h>
  24#include <linux/kernel.h>
  25#include <linux/module.h>
  26#include <linux/usb.h>
  27#include <linux/usb/input.h>
  28#include <media/rc-core.h>
  29
  30#define DRIVER_DESC             "IgorPlug-USB IR Receiver"
  31#define DRIVER_NAME             "igorplugusb"
  32
  33#define HEADERLEN               3
  34#define BUFLEN                  36
  35#define MAX_PACKET              (HEADERLEN + BUFLEN)
  36
  37#define SET_INFRABUFFER_EMPTY   1
  38#define GET_INFRACODE           2
  39
  40
  41struct igorplugusb {
  42        struct rc_dev *rc;
  43        struct device *dev;
  44
  45        struct urb *urb;
  46        struct usb_ctrlrequest request;
  47
  48        struct timer_list timer;
  49
  50        uint8_t buf_in[MAX_PACKET];
  51
  52        char phys[64];
  53};
  54
  55static void igorplugusb_cmd(struct igorplugusb *ir, int cmd);
  56
  57static void igorplugusb_irdata(struct igorplugusb *ir, unsigned len)
  58{
  59        DEFINE_IR_RAW_EVENT(rawir);
  60        unsigned i, start, overflow;
  61
  62        dev_dbg(ir->dev, "irdata: %*ph (len=%u)", len, ir->buf_in, len);
  63
  64        /*
  65         * If more than 36 pulses and spaces follow each other, the igorplugusb
  66         * overwrites its buffer from the beginning. The overflow value is the
  67         * last offset which was not overwritten. Everything from this offset
  68         * onwards occurred before everything until this offset.
  69         */
  70        overflow = ir->buf_in[2];
  71        i = start = overflow + HEADERLEN;
  72
  73        if (start >= len) {
  74                dev_err(ir->dev, "receive overflow invalid: %u", overflow);
  75        } else {
  76                if (overflow > 0)
  77                        dev_warn(ir->dev, "receive overflow, at least %u lost",
  78                                                                overflow);
  79
  80                do {
  81                        rawir.duration = ir->buf_in[i] * 85333;
  82                        rawir.pulse = i & 1;
  83
  84                        ir_raw_event_store_with_filter(ir->rc, &rawir);
  85
  86                        if (++i == len)
  87                                i = HEADERLEN;
  88                } while (i != start);
  89
  90                /* add a trailing space */
  91                rawir.duration = ir->rc->timeout;
  92                rawir.pulse = false;
  93                ir_raw_event_store_with_filter(ir->rc, &rawir);
  94
  95                ir_raw_event_handle(ir->rc);
  96        }
  97
  98        igorplugusb_cmd(ir, SET_INFRABUFFER_EMPTY);
  99}
 100
 101static void igorplugusb_callback(struct urb *urb)
 102{
 103        struct usb_ctrlrequest *req;
 104        struct igorplugusb *ir = urb->context;
 105
 106        req = (struct usb_ctrlrequest *)urb->setup_packet;
 107
 108        switch (urb->status) {
 109        case 0:
 110                if (req->bRequest == GET_INFRACODE &&
 111                                        urb->actual_length > HEADERLEN)
 112                        igorplugusb_irdata(ir, urb->actual_length);
 113                else /* request IR */
 114                        mod_timer(&ir->timer, jiffies + msecs_to_jiffies(50));
 115                break;
 116        case -EPROTO:
 117        case -ECONNRESET:
 118        case -ENOENT:
 119        case -ESHUTDOWN:
 120                usb_unlink_urb(urb);
 121                return;
 122        default:
 123                dev_warn(ir->dev, "Error: urb status = %d\n", urb->status);
 124                igorplugusb_cmd(ir, SET_INFRABUFFER_EMPTY);
 125                break;
 126        }
 127}
 128
 129static void igorplugusb_cmd(struct igorplugusb *ir, int cmd)
 130{
 131        int ret;
 132
 133        ir->request.bRequest = cmd;
 134        ir->urb->transfer_flags = 0;
 135        ret = usb_submit_urb(ir->urb, GFP_ATOMIC);
 136        if (ret)
 137                dev_err(ir->dev, "submit urb failed: %d", ret);
 138}
 139
 140static void igorplugusb_timer(unsigned long data)
 141{
 142        struct igorplugusb *ir = (struct igorplugusb *)data;
 143
 144        igorplugusb_cmd(ir, GET_INFRACODE);
 145}
 146
 147static int igorplugusb_probe(struct usb_interface *intf,
 148                                        const struct usb_device_id *id)
 149{
 150        struct usb_device *udev;
 151        struct usb_host_interface *idesc;
 152        struct usb_endpoint_descriptor *ep;
 153        struct igorplugusb *ir;
 154        struct rc_dev *rc;
 155        int ret;
 156
 157        udev = interface_to_usbdev(intf);
 158        idesc = intf->cur_altsetting;
 159
 160        if (idesc->desc.bNumEndpoints != 1) {
 161                dev_err(&intf->dev, "incorrect number of endpoints");
 162                return -ENODEV;
 163        }
 164
 165        ep = &idesc->endpoint[0].desc;
 166        if (!usb_endpoint_dir_in(ep) || !usb_endpoint_xfer_control(ep)) {
 167                dev_err(&intf->dev, "endpoint incorrect");
 168                return -ENODEV;
 169        }
 170
 171        ir = devm_kzalloc(&intf->dev, sizeof(*ir), GFP_KERNEL);
 172        if (!ir)
 173                return -ENOMEM;
 174
 175        ir->dev = &intf->dev;
 176
 177        setup_timer(&ir->timer, igorplugusb_timer, (unsigned long)ir);
 178
 179        ir->request.bRequest = GET_INFRACODE;
 180        ir->request.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN;
 181        ir->request.wLength = cpu_to_le16(sizeof(ir->buf_in));
 182
 183        ir->urb = usb_alloc_urb(0, GFP_KERNEL);
 184        if (!ir->urb)
 185                return -ENOMEM;
 186
 187        usb_fill_control_urb(ir->urb, udev,
 188                usb_rcvctrlpipe(udev, 0), (uint8_t *)&ir->request,
 189                ir->buf_in, sizeof(ir->buf_in), igorplugusb_callback, ir);
 190
 191        usb_make_path(udev, ir->phys, sizeof(ir->phys));
 192
 193        rc = rc_allocate_device();
 194        rc->input_name = DRIVER_DESC;
 195        rc->input_phys = ir->phys;
 196        usb_to_input_id(udev, &rc->input_id);
 197        rc->dev.parent = &intf->dev;
 198        rc->driver_type = RC_DRIVER_IR_RAW;
 199        /*
 200         * This device can only store 36 pulses + spaces, which is not enough
 201         * for the NEC protocol and many others.
 202         */
 203        rc->allowed_protocols = RC_BIT_ALL & ~(RC_BIT_NEC | RC_BIT_RC6_6A_20 |
 204                        RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE |
 205                        RC_BIT_SONY20 | RC_BIT_MCE_KBD | RC_BIT_SANYO);
 206
 207        rc->priv = ir;
 208        rc->driver_name = DRIVER_NAME;
 209        rc->map_name = RC_MAP_HAUPPAUGE;
 210        rc->timeout = MS_TO_NS(100);
 211        rc->rx_resolution = 85333;
 212
 213        ir->rc = rc;
 214        ret = rc_register_device(rc);
 215        if (ret) {
 216                dev_err(&intf->dev, "failed to register rc device: %d", ret);
 217                rc_free_device(rc);
 218                usb_free_urb(ir->urb);
 219                return ret;
 220        }
 221
 222        usb_set_intfdata(intf, ir);
 223
 224        igorplugusb_cmd(ir, SET_INFRABUFFER_EMPTY);
 225
 226        return 0;
 227}
 228
 229static void igorplugusb_disconnect(struct usb_interface *intf)
 230{
 231        struct igorplugusb *ir = usb_get_intfdata(intf);
 232
 233        rc_unregister_device(ir->rc);
 234        del_timer_sync(&ir->timer);
 235        usb_set_intfdata(intf, NULL);
 236        usb_kill_urb(ir->urb);
 237        usb_free_urb(ir->urb);
 238}
 239
 240static struct usb_device_id igorplugusb_table[] = {
 241        /* Igor Plug USB (Atmel's Manufact. ID) */
 242        { USB_DEVICE(0x03eb, 0x0002) },
 243        /* Fit PC2 Infrared Adapter */
 244        { USB_DEVICE(0x03eb, 0x21fe) },
 245        /* Terminating entry */
 246        { }
 247};
 248
 249static struct usb_driver igorplugusb_driver = {
 250        .name = DRIVER_NAME,
 251        .probe = igorplugusb_probe,
 252        .disconnect = igorplugusb_disconnect,
 253        .id_table = igorplugusb_table
 254};
 255
 256module_usb_driver(igorplugusb_driver);
 257
 258MODULE_DESCRIPTION(DRIVER_DESC);
 259MODULE_AUTHOR("Sean Young <sean@mess.org>");
 260MODULE_LICENSE("GPL");
 261MODULE_DEVICE_TABLE(usb, igorplugusb_table);
 262