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