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