linux/drivers/media/rc/iguanair.c
<<
>>
Prefs
   1/*
   2 * IguanaWorks USB IR Transceiver support
   3 *
   4 * Copyright (C) 2012 Sean Young <sean@mess.org>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16
  17#include <linux/device.h>
  18#include <linux/kernel.h>
  19#include <linux/module.h>
  20#include <linux/usb.h>
  21#include <linux/usb/input.h>
  22#include <linux/slab.h>
  23#include <linux/completion.h>
  24#include <media/rc-core.h>
  25
  26#define DRIVER_NAME "iguanair"
  27#define BUF_SIZE 152
  28
  29struct iguanair {
  30        struct rc_dev *rc;
  31
  32        struct device *dev;
  33        struct usb_device *udev;
  34
  35        uint16_t version;
  36        uint8_t bufsize;
  37        uint8_t cycle_overhead;
  38
  39        struct mutex lock;
  40
  41        /* receiver support */
  42        bool receiver_on;
  43        dma_addr_t dma_in, dma_out;
  44        uint8_t *buf_in;
  45        struct urb *urb_in, *urb_out;
  46        struct completion completion;
  47
  48        /* transmit support */
  49        bool tx_overflow;
  50        uint32_t carrier;
  51        struct send_packet *packet;
  52
  53        char name[64];
  54        char phys[64];
  55};
  56
  57#define CMD_NOP                 0x00
  58#define CMD_GET_VERSION         0x01
  59#define CMD_GET_BUFSIZE         0x11
  60#define CMD_GET_FEATURES        0x10
  61#define CMD_SEND                0x15
  62#define CMD_EXECUTE             0x1f
  63#define CMD_RX_OVERFLOW         0x31
  64#define CMD_TX_OVERFLOW         0x32
  65#define CMD_RECEIVER_ON         0x12
  66#define CMD_RECEIVER_OFF        0x14
  67
  68#define DIR_IN                  0xdc
  69#define DIR_OUT                 0xcd
  70
  71#define MAX_IN_PACKET           8u
  72#define MAX_OUT_PACKET          (sizeof(struct send_packet) + BUF_SIZE)
  73#define TIMEOUT                 1000
  74#define RX_RESOLUTION           21333
  75
  76struct packet {
  77        uint16_t start;
  78        uint8_t direction;
  79        uint8_t cmd;
  80};
  81
  82struct send_packet {
  83        struct packet header;
  84        uint8_t length;
  85        uint8_t channels;
  86        uint8_t busy7;
  87        uint8_t busy4;
  88        uint8_t payload[0];
  89};
  90
  91static void process_ir_data(struct iguanair *ir, unsigned len)
  92{
  93        if (len >= 4 && ir->buf_in[0] == 0 && ir->buf_in[1] == 0) {
  94                switch (ir->buf_in[3]) {
  95                case CMD_GET_VERSION:
  96                        if (len == 6) {
  97                                ir->version = (ir->buf_in[5] << 8) |
  98                                                        ir->buf_in[4];
  99                                complete(&ir->completion);
 100                        }
 101                        break;
 102                case CMD_GET_BUFSIZE:
 103                        if (len >= 5) {
 104                                ir->bufsize = ir->buf_in[4];
 105                                complete(&ir->completion);
 106                        }
 107                        break;
 108                case CMD_GET_FEATURES:
 109                        if (len > 5) {
 110                                ir->cycle_overhead = ir->buf_in[5];
 111                                complete(&ir->completion);
 112                        }
 113                        break;
 114                case CMD_TX_OVERFLOW:
 115                        ir->tx_overflow = true;
 116                        /* fall through */
 117                case CMD_RECEIVER_OFF:
 118                case CMD_RECEIVER_ON:
 119                case CMD_SEND:
 120                        complete(&ir->completion);
 121                        break;
 122                case CMD_RX_OVERFLOW:
 123                        dev_warn(ir->dev, "receive overflow\n");
 124                        ir_raw_event_reset(ir->rc);
 125                        break;
 126                default:
 127                        dev_warn(ir->dev, "control code %02x received\n",
 128                                                        ir->buf_in[3]);
 129                        break;
 130                }
 131        } else if (len >= 7) {
 132                DEFINE_IR_RAW_EVENT(rawir);
 133                unsigned i;
 134                bool event = false;
 135
 136                init_ir_raw_event(&rawir);
 137
 138                for (i = 0; i < 7; i++) {
 139                        if (ir->buf_in[i] == 0x80) {
 140                                rawir.pulse = false;
 141                                rawir.duration = US_TO_NS(21845);
 142                        } else {
 143                                rawir.pulse = (ir->buf_in[i] & 0x80) == 0;
 144                                rawir.duration = ((ir->buf_in[i] & 0x7f) + 1) *
 145                                                                 RX_RESOLUTION;
 146                        }
 147
 148                        if (ir_raw_event_store_with_filter(ir->rc, &rawir))
 149                                event = true;
 150                }
 151
 152                if (event)
 153                        ir_raw_event_handle(ir->rc);
 154        }
 155}
 156
 157static void iguanair_rx(struct urb *urb)
 158{
 159        struct iguanair *ir;
 160        int rc;
 161
 162        if (!urb)
 163                return;
 164
 165        ir = urb->context;
 166        if (!ir) {
 167                usb_unlink_urb(urb);
 168                return;
 169        }
 170
 171        switch (urb->status) {
 172        case 0:
 173                process_ir_data(ir, urb->actual_length);
 174                break;
 175        case -ECONNRESET:
 176        case -ENOENT:
 177        case -ESHUTDOWN:
 178                usb_unlink_urb(urb);
 179                return;
 180        case -EPIPE:
 181        default:
 182                dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status);
 183                break;
 184        }
 185
 186        rc = usb_submit_urb(urb, GFP_ATOMIC);
 187        if (rc && rc != -ENODEV)
 188                dev_warn(ir->dev, "failed to resubmit urb: %d\n", rc);
 189}
 190
 191static void iguanair_irq_out(struct urb *urb)
 192{
 193        struct iguanair *ir = urb->context;
 194
 195        if (urb->status)
 196                dev_dbg(ir->dev, "Error: out urb status = %d\n", urb->status);
 197
 198        /* if we sent an nop packet, do not expect a response */
 199        if (urb->status == 0 && ir->packet->header.cmd == CMD_NOP)
 200                complete(&ir->completion);
 201}
 202
 203static int iguanair_send(struct iguanair *ir, unsigned size)
 204{
 205        int rc;
 206
 207        reinit_completion(&ir->completion);
 208
 209        ir->urb_out->transfer_buffer_length = size;
 210        rc = usb_submit_urb(ir->urb_out, GFP_KERNEL);
 211        if (rc)
 212                return rc;
 213
 214        if (wait_for_completion_timeout(&ir->completion, TIMEOUT) == 0)
 215                return -ETIMEDOUT;
 216
 217        return rc;
 218}
 219
 220static int iguanair_get_features(struct iguanair *ir)
 221{
 222        int rc;
 223
 224        /*
 225         * On cold boot, the iguanair initializes on the first packet
 226         * received but does not process that packet. Send an empty
 227         * packet.
 228         */
 229        ir->packet->header.start = 0;
 230        ir->packet->header.direction = DIR_OUT;
 231        ir->packet->header.cmd = CMD_NOP;
 232        iguanair_send(ir, sizeof(ir->packet->header));
 233
 234        ir->packet->header.cmd = CMD_GET_VERSION;
 235        rc = iguanair_send(ir, sizeof(ir->packet->header));
 236        if (rc) {
 237                dev_info(ir->dev, "failed to get version\n");
 238                goto out;
 239        }
 240
 241        if (ir->version < 0x205) {
 242                dev_err(ir->dev, "firmware 0x%04x is too old\n", ir->version);
 243                rc = -ENODEV;
 244                goto out;
 245        }
 246
 247        ir->bufsize = 150;
 248        ir->cycle_overhead = 65;
 249
 250        ir->packet->header.cmd = CMD_GET_BUFSIZE;
 251
 252        rc = iguanair_send(ir, sizeof(ir->packet->header));
 253        if (rc) {
 254                dev_info(ir->dev, "failed to get buffer size\n");
 255                goto out;
 256        }
 257
 258        if (ir->bufsize > BUF_SIZE) {
 259                dev_info(ir->dev, "buffer size %u larger than expected\n",
 260                                                                ir->bufsize);
 261                ir->bufsize = BUF_SIZE;
 262        }
 263
 264        ir->packet->header.cmd = CMD_GET_FEATURES;
 265
 266        rc = iguanair_send(ir, sizeof(ir->packet->header));
 267        if (rc)
 268                dev_info(ir->dev, "failed to get features\n");
 269out:
 270        return rc;
 271}
 272
 273static int iguanair_receiver(struct iguanair *ir, bool enable)
 274{
 275        ir->packet->header.start = 0;
 276        ir->packet->header.direction = DIR_OUT;
 277        ir->packet->header.cmd = enable ? CMD_RECEIVER_ON : CMD_RECEIVER_OFF;
 278
 279        if (enable)
 280                ir_raw_event_reset(ir->rc);
 281
 282        return iguanair_send(ir, sizeof(ir->packet->header));
 283}
 284
 285/*
 286 * The iguanair creates the carrier by busy spinning after each half period.
 287 * This is counted in CPU cycles, with the CPU running at 24MHz. It is
 288 * broken down into 7-cycles and 4-cyles delays, with a preference for
 289 * 4-cycle delays, minus the overhead of the loop itself (cycle_overhead).
 290 */
 291static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier)
 292{
 293        struct iguanair *ir = dev->priv;
 294
 295        if (carrier < 25000 || carrier > 150000)
 296                return -EINVAL;
 297
 298        mutex_lock(&ir->lock);
 299
 300        if (carrier != ir->carrier) {
 301                uint32_t cycles, fours, sevens;
 302
 303                ir->carrier = carrier;
 304
 305                cycles = DIV_ROUND_CLOSEST(24000000, carrier * 2) -
 306                                                        ir->cycle_overhead;
 307
 308                /*
 309                 * Calculate minimum number of 7 cycles needed so
 310                 * we are left with a multiple of 4; so we want to have
 311                 * (sevens * 7) & 3 == cycles & 3
 312                 */
 313                sevens = (4 - cycles) & 3;
 314                fours = (cycles - sevens * 7) / 4;
 315
 316                /*
 317                 * The firmware interprets these values as a relative offset
 318                 * for a branch. Immediately following the branches, there
 319                 * 4 instructions of 7 cycles (2 bytes each) and 110
 320                 * instructions of 4 cycles (1 byte each). A relative branch
 321                 * of 0 will execute all of them, branch further for less
 322                 * cycle burning.
 323                 */
 324                ir->packet->busy7 = (4 - sevens) * 2;
 325                ir->packet->busy4 = 110 - fours;
 326        }
 327
 328        mutex_unlock(&ir->lock);
 329
 330        return 0;
 331}
 332
 333static int iguanair_set_tx_mask(struct rc_dev *dev, uint32_t mask)
 334{
 335        struct iguanair *ir = dev->priv;
 336
 337        if (mask > 15)
 338                return 4;
 339
 340        mutex_lock(&ir->lock);
 341        ir->packet->channels = mask << 4;
 342        mutex_unlock(&ir->lock);
 343
 344        return 0;
 345}
 346
 347static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 348{
 349        struct iguanair *ir = dev->priv;
 350        unsigned int i, size, p, periods;
 351        int rc;
 352
 353        mutex_lock(&ir->lock);
 354
 355        /* convert from us to carrier periods */
 356        for (i = size = 0; i < count; i++) {
 357                periods = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000);
 358                while (periods) {
 359                        p = min(periods, 127u);
 360                        if (size >= ir->bufsize) {
 361                                rc = -EINVAL;
 362                                goto out;
 363                        }
 364                        ir->packet->payload[size++] = p | ((i & 1) ? 0x80 : 0);
 365                        periods -= p;
 366                }
 367        }
 368
 369        ir->packet->header.start = 0;
 370        ir->packet->header.direction = DIR_OUT;
 371        ir->packet->header.cmd = CMD_SEND;
 372        ir->packet->length = size;
 373
 374        ir->tx_overflow = false;
 375
 376        rc = iguanair_send(ir, sizeof(*ir->packet) + size);
 377
 378        if (rc == 0 && ir->tx_overflow)
 379                rc = -EOVERFLOW;
 380
 381out:
 382        mutex_unlock(&ir->lock);
 383
 384        return rc ? rc : count;
 385}
 386
 387static int iguanair_open(struct rc_dev *rdev)
 388{
 389        struct iguanair *ir = rdev->priv;
 390        int rc;
 391
 392        mutex_lock(&ir->lock);
 393
 394        rc = iguanair_receiver(ir, true);
 395        if (rc == 0)
 396                ir->receiver_on = true;
 397
 398        mutex_unlock(&ir->lock);
 399
 400        return rc;
 401}
 402
 403static void iguanair_close(struct rc_dev *rdev)
 404{
 405        struct iguanair *ir = rdev->priv;
 406        int rc;
 407
 408        mutex_lock(&ir->lock);
 409
 410        rc = iguanair_receiver(ir, false);
 411        ir->receiver_on = false;
 412        if (rc && rc != -ENODEV)
 413                dev_warn(ir->dev, "failed to disable receiver: %d\n", rc);
 414
 415        mutex_unlock(&ir->lock);
 416}
 417
 418static int iguanair_probe(struct usb_interface *intf,
 419                          const struct usb_device_id *id)
 420{
 421        struct usb_device *udev = interface_to_usbdev(intf);
 422        struct iguanair *ir;
 423        struct rc_dev *rc;
 424        int ret, pipein, pipeout;
 425        struct usb_host_interface *idesc;
 426
 427        ir = kzalloc(sizeof(*ir), GFP_KERNEL);
 428        rc = rc_allocate_device(RC_DRIVER_IR_RAW);
 429        if (!ir || !rc) {
 430                ret = -ENOMEM;
 431                goto out;
 432        }
 433
 434        ir->buf_in = usb_alloc_coherent(udev, MAX_IN_PACKET, GFP_KERNEL,
 435                                                                &ir->dma_in);
 436        ir->packet = usb_alloc_coherent(udev, MAX_OUT_PACKET, GFP_KERNEL,
 437                                                                &ir->dma_out);
 438        ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
 439        ir->urb_out = usb_alloc_urb(0, GFP_KERNEL);
 440
 441        if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out) {
 442                ret = -ENOMEM;
 443                goto out;
 444        }
 445
 446        idesc = intf->altsetting;
 447
 448        if (idesc->desc.bNumEndpoints < 2) {
 449                ret = -ENODEV;
 450                goto out;
 451        }
 452
 453        ir->rc = rc;
 454        ir->dev = &intf->dev;
 455        ir->udev = udev;
 456        mutex_init(&ir->lock);
 457
 458        init_completion(&ir->completion);
 459        pipeout = usb_sndintpipe(udev,
 460                                idesc->endpoint[1].desc.bEndpointAddress);
 461        usb_fill_int_urb(ir->urb_out, udev, pipeout, ir->packet, MAX_OUT_PACKET,
 462                                                iguanair_irq_out, ir, 1);
 463        ir->urb_out->transfer_dma = ir->dma_out;
 464        ir->urb_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 465
 466        pipein = usb_rcvintpipe(udev, idesc->endpoint[0].desc.bEndpointAddress);
 467        usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_IN_PACKET,
 468                                                         iguanair_rx, ir, 1);
 469        ir->urb_in->transfer_dma = ir->dma_in;
 470        ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 471
 472        ret = usb_submit_urb(ir->urb_in, GFP_KERNEL);
 473        if (ret) {
 474                dev_warn(&intf->dev, "failed to submit urb: %d\n", ret);
 475                goto out;
 476        }
 477
 478        ret = iguanair_get_features(ir);
 479        if (ret)
 480                goto out2;
 481
 482        snprintf(ir->name, sizeof(ir->name),
 483                "IguanaWorks USB IR Transceiver version 0x%04x", ir->version);
 484
 485        usb_make_path(ir->udev, ir->phys, sizeof(ir->phys));
 486
 487        rc->device_name = ir->name;
 488        rc->input_phys = ir->phys;
 489        usb_to_input_id(ir->udev, &rc->input_id);
 490        rc->dev.parent = &intf->dev;
 491        rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
 492        rc->priv = ir;
 493        rc->open = iguanair_open;
 494        rc->close = iguanair_close;
 495        rc->s_tx_mask = iguanair_set_tx_mask;
 496        rc->s_tx_carrier = iguanair_set_tx_carrier;
 497        rc->tx_ir = iguanair_tx;
 498        rc->driver_name = DRIVER_NAME;
 499        rc->map_name = RC_MAP_RC6_MCE;
 500        rc->min_timeout = 1;
 501        rc->timeout = IR_DEFAULT_TIMEOUT;
 502        rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
 503        rc->rx_resolution = RX_RESOLUTION;
 504
 505        iguanair_set_tx_carrier(rc, 38000);
 506        iguanair_set_tx_mask(rc, 0);
 507
 508        ret = rc_register_device(rc);
 509        if (ret < 0) {
 510                dev_err(&intf->dev, "failed to register rc device %d", ret);
 511                goto out2;
 512        }
 513
 514        usb_set_intfdata(intf, ir);
 515
 516        return 0;
 517out2:
 518        usb_kill_urb(ir->urb_in);
 519        usb_kill_urb(ir->urb_out);
 520out:
 521        if (ir) {
 522                usb_free_urb(ir->urb_in);
 523                usb_free_urb(ir->urb_out);
 524                usb_free_coherent(udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in);
 525                usb_free_coherent(udev, MAX_OUT_PACKET, ir->packet,
 526                                                                ir->dma_out);
 527        }
 528        rc_free_device(rc);
 529        kfree(ir);
 530        return ret;
 531}
 532
 533static void iguanair_disconnect(struct usb_interface *intf)
 534{
 535        struct iguanair *ir = usb_get_intfdata(intf);
 536
 537        rc_unregister_device(ir->rc);
 538        usb_set_intfdata(intf, NULL);
 539        usb_kill_urb(ir->urb_in);
 540        usb_kill_urb(ir->urb_out);
 541        usb_free_urb(ir->urb_in);
 542        usb_free_urb(ir->urb_out);
 543        usb_free_coherent(ir->udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in);
 544        usb_free_coherent(ir->udev, MAX_OUT_PACKET, ir->packet, ir->dma_out);
 545        kfree(ir);
 546}
 547
 548static int iguanair_suspend(struct usb_interface *intf, pm_message_t message)
 549{
 550        struct iguanair *ir = usb_get_intfdata(intf);
 551        int rc = 0;
 552
 553        mutex_lock(&ir->lock);
 554
 555        if (ir->receiver_on) {
 556                rc = iguanair_receiver(ir, false);
 557                if (rc)
 558                        dev_warn(ir->dev, "failed to disable receiver for suspend\n");
 559        }
 560
 561        usb_kill_urb(ir->urb_in);
 562        usb_kill_urb(ir->urb_out);
 563
 564        mutex_unlock(&ir->lock);
 565
 566        return rc;
 567}
 568
 569static int iguanair_resume(struct usb_interface *intf)
 570{
 571        struct iguanair *ir = usb_get_intfdata(intf);
 572        int rc = 0;
 573
 574        mutex_lock(&ir->lock);
 575
 576        rc = usb_submit_urb(ir->urb_in, GFP_KERNEL);
 577        if (rc)
 578                dev_warn(&intf->dev, "failed to submit urb: %d\n", rc);
 579
 580        if (ir->receiver_on) {
 581                rc = iguanair_receiver(ir, true);
 582                if (rc)
 583                        dev_warn(ir->dev, "failed to enable receiver after resume\n");
 584        }
 585
 586        mutex_unlock(&ir->lock);
 587
 588        return rc;
 589}
 590
 591static const struct usb_device_id iguanair_table[] = {
 592        { USB_DEVICE(0x1781, 0x0938) },
 593        { }
 594};
 595
 596static struct usb_driver iguanair_driver = {
 597        .name = DRIVER_NAME,
 598        .probe = iguanair_probe,
 599        .disconnect = iguanair_disconnect,
 600        .suspend = iguanair_suspend,
 601        .resume = iguanair_resume,
 602        .reset_resume = iguanair_resume,
 603        .id_table = iguanair_table,
 604        .soft_unbind = 1        /* we want to disable receiver on unbind */
 605};
 606
 607module_usb_driver(iguanair_driver);
 608
 609MODULE_DESCRIPTION("IguanaWorks USB IR Transceiver");
 610MODULE_AUTHOR("Sean Young <sean@mess.org>");
 611MODULE_LICENSE("GPL");
 612MODULE_DEVICE_TABLE(usb, iguanair_table);
 613
 614