linux/drivers/staging/media/lirc/lirc_imon.c
<<
>>
Prefs
   1/*
   2 *   lirc_imon.c:  LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD
   3 *                 including the iMON PAD model
   4 *
   5 *   Copyright(C) 2004  Venky Raju(dev@venky.ws)
   6 *   Copyright(C) 2009  Jarod Wilson <jarod@wilsonet.com>
   7 *
   8 *   lirc_imon is free software; you can redistribute it and/or modify
   9 *   it under the terms of the GNU General Public License as published by
  10 *   the Free Software Foundation; either version 2 of the License, or
  11 *   (at your option) any later version.
  12 *
  13 *   This program is distributed in the hope that it will be useful,
  14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 *   GNU General Public License for more details.
  17 *
  18 *   You should have received a copy of the GNU General Public License
  19 *   along with this program; if not, write to the Free Software
  20 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21 */
  22
  23#include <linux/errno.h>
  24#include <linux/init.h>
  25#include <linux/kernel.h>
  26#include <linux/module.h>
  27#include <linux/slab.h>
  28#include <linux/uaccess.h>
  29#include <linux/usb.h>
  30
  31#include <media/lirc.h>
  32#include <media/lirc_dev.h>
  33
  34
  35#define MOD_AUTHOR      "Venky Raju <dev@venky.ws>"
  36#define MOD_DESC        "Driver for SoundGraph iMON MultiMedia IR/Display"
  37#define MOD_NAME        "lirc_imon"
  38#define MOD_VERSION     "0.8"
  39
  40#define DISPLAY_MINOR_BASE      144
  41#define DEVICE_NAME     "lcd%d"
  42
  43#define BUF_CHUNK_SIZE  4
  44#define BUF_SIZE        128
  45
  46#define BIT_DURATION    250     /* each bit received is 250us */
  47
  48/*** P R O T O T Y P E S ***/
  49
  50/* USB Callback prototypes */
  51static int imon_probe(struct usb_interface *interface,
  52                      const struct usb_device_id *id);
  53static void imon_disconnect(struct usb_interface *interface);
  54static void usb_rx_callback(struct urb *urb);
  55static void usb_tx_callback(struct urb *urb);
  56
  57/* suspend/resume support */
  58static int imon_resume(struct usb_interface *intf);
  59static int imon_suspend(struct usb_interface *intf, pm_message_t message);
  60
  61/* Display file_operations function prototypes */
  62static int display_open(struct inode *inode, struct file *file);
  63static int display_close(struct inode *inode, struct file *file);
  64
  65/* VFD write operation */
  66static ssize_t vfd_write(struct file *file, const char *buf,
  67                         size_t n_bytes, loff_t *pos);
  68
  69/* LIRC driver function prototypes */
  70static int ir_open(void *data);
  71static void ir_close(void *data);
  72
  73/* Driver init/exit prototypes */
  74static int __init imon_init(void);
  75static void __exit imon_exit(void);
  76
  77/*** G L O B A L S ***/
  78#define IMON_DATA_BUF_SZ        35
  79
  80struct imon_context {
  81        struct usb_device *usbdev;
  82        /* Newer devices have two interfaces */
  83        int display;                    /* not all controllers do */
  84        int display_isopen;             /* display port has been opened */
  85        int ir_isopen;                  /* IR port open */
  86        int dev_present;                /* USB device presence */
  87        struct mutex ctx_lock;          /* to lock this object */
  88        wait_queue_head_t remove_ok;    /* For unexpected USB disconnects */
  89
  90        int vfd_proto_6p;               /* some VFD require a 6th packet */
  91
  92        struct lirc_driver *driver;
  93        struct usb_endpoint_descriptor *rx_endpoint;
  94        struct usb_endpoint_descriptor *tx_endpoint;
  95        struct urb *rx_urb;
  96        struct urb *tx_urb;
  97        unsigned char usb_rx_buf[8];
  98        unsigned char usb_tx_buf[8];
  99
 100        struct rx_data {
 101                int count;              /* length of 0 or 1 sequence */
 102                int prev_bit;           /* logic level of sequence */
 103                int initial_space;      /* initial space flag */
 104        } rx;
 105
 106        struct tx_t {
 107                unsigned char data_buf[IMON_DATA_BUF_SZ]; /* user data buffer */
 108                struct completion finished;     /* wait for write to finish */
 109                atomic_t busy;                  /* write in progress */
 110                int status;                     /* status of tx completion */
 111        } tx;
 112};
 113
 114static const struct file_operations display_fops = {
 115        .owner          = THIS_MODULE,
 116        .open           = &display_open,
 117        .write          = &vfd_write,
 118        .release        = &display_close,
 119        .llseek         = noop_llseek,
 120};
 121
 122/*
 123 * USB Device ID for iMON USB Control Boards
 124 *
 125 * The Windows drivers contain 6 different inf files, more or less one for
 126 * each new device until the 0x0034-0x0046 devices, which all use the same
 127 * driver. Some of the devices in the 34-46 range haven't been definitively
 128 * identified yet. Early devices have either a TriGem Computer, Inc. or a
 129 * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later
 130 * devices use the SoundGraph vendor ID (0x15c2).
 131 */
 132static struct usb_device_id imon_usb_id_table[] = {
 133        /* TriGem iMON (IR only) -- TG_iMON.inf */
 134        { USB_DEVICE(0x0aa8, 0x8001) },
 135
 136        /* SoundGraph iMON (IR only) -- sg_imon.inf */
 137        { USB_DEVICE(0x04e8, 0xff30) },
 138
 139        /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */
 140        { USB_DEVICE(0x0aa8, 0xffda) },
 141
 142        /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */
 143        { USB_DEVICE(0x15c2, 0xffda) },
 144
 145        {}
 146};
 147
 148/* Some iMON VFD models requires a 6th packet for VFD writes */
 149static struct usb_device_id vfd_proto_6p_list[] = {
 150        { USB_DEVICE(0x15c2, 0xffda) },
 151        {}
 152};
 153
 154/* Some iMON devices have no lcd/vfd, don't set one up */
 155static struct usb_device_id ir_only_list[] = {
 156        { USB_DEVICE(0x0aa8, 0x8001) },
 157        { USB_DEVICE(0x04e8, 0xff30) },
 158        {}
 159};
 160
 161/* USB Device data */
 162static struct usb_driver imon_driver = {
 163        .name           = MOD_NAME,
 164        .probe          = imon_probe,
 165        .disconnect     = imon_disconnect,
 166        .suspend        = imon_suspend,
 167        .resume         = imon_resume,
 168        .id_table       = imon_usb_id_table,
 169};
 170
 171static struct usb_class_driver imon_class = {
 172        .name           = DEVICE_NAME,
 173        .fops           = &display_fops,
 174        .minor_base     = DISPLAY_MINOR_BASE,
 175};
 176
 177/* to prevent races between open() and disconnect(), probing, etc */
 178static DEFINE_MUTEX(driver_lock);
 179
 180static int debug;
 181
 182/***  M O D U L E   C O D E ***/
 183
 184MODULE_AUTHOR(MOD_AUTHOR);
 185MODULE_DESCRIPTION(MOD_DESC);
 186MODULE_VERSION(MOD_VERSION);
 187MODULE_LICENSE("GPL");
 188MODULE_DEVICE_TABLE(usb, imon_usb_id_table);
 189module_param(debug, int, S_IRUGO | S_IWUSR);
 190MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)");
 191
 192static void free_imon_context(struct imon_context *context)
 193{
 194        struct device *dev = context->driver->dev;
 195        usb_free_urb(context->tx_urb);
 196        usb_free_urb(context->rx_urb);
 197        lirc_buffer_free(context->driver->rbuf);
 198        kfree(context->driver->rbuf);
 199        kfree(context->driver);
 200        kfree(context);
 201
 202        dev_dbg(dev, "%s: iMON context freed\n", __func__);
 203}
 204
 205static void deregister_from_lirc(struct imon_context *context)
 206{
 207        int retval;
 208        int minor = context->driver->minor;
 209
 210        retval = lirc_unregister_driver(minor);
 211        if (retval)
 212                err("%s: unable to deregister from lirc(%d)",
 213                        __func__, retval);
 214        else
 215                printk(KERN_INFO MOD_NAME ": Deregistered iMON driver "
 216                       "(minor:%d)\n", minor);
 217
 218}
 219
 220/**
 221 * Called when the Display device (e.g. /dev/lcd0)
 222 * is opened by the application.
 223 */
 224static int display_open(struct inode *inode, struct file *file)
 225{
 226        struct usb_interface *interface;
 227        struct imon_context *context = NULL;
 228        int subminor;
 229        int retval = 0;
 230
 231        /* prevent races with disconnect */
 232        mutex_lock(&driver_lock);
 233
 234        subminor = iminor(inode);
 235        interface = usb_find_interface(&imon_driver, subminor);
 236        if (!interface) {
 237                err("%s: could not find interface for minor %d",
 238                    __func__, subminor);
 239                retval = -ENODEV;
 240                goto exit;
 241        }
 242        context = usb_get_intfdata(interface);
 243
 244        if (!context) {
 245                err("%s: no context found for minor %d",
 246                                        __func__, subminor);
 247                retval = -ENODEV;
 248                goto exit;
 249        }
 250
 251        mutex_lock(&context->ctx_lock);
 252
 253        if (!context->display) {
 254                err("%s: display not supported by device", __func__);
 255                retval = -ENODEV;
 256        } else if (context->display_isopen) {
 257                err("%s: display port is already open", __func__);
 258                retval = -EBUSY;
 259        } else {
 260                context->display_isopen = 1;
 261                file->private_data = context;
 262                dev_info(context->driver->dev, "display port opened\n");
 263        }
 264
 265        mutex_unlock(&context->ctx_lock);
 266
 267exit:
 268        mutex_unlock(&driver_lock);
 269        return retval;
 270}
 271
 272/**
 273 * Called when the display device (e.g. /dev/lcd0)
 274 * is closed by the application.
 275 */
 276static int display_close(struct inode *inode, struct file *file)
 277{
 278        struct imon_context *context = NULL;
 279        int retval = 0;
 280
 281        context = file->private_data;
 282
 283        if (!context) {
 284                err("%s: no context for device", __func__);
 285                return -ENODEV;
 286        }
 287
 288        mutex_lock(&context->ctx_lock);
 289
 290        if (!context->display) {
 291                err("%s: display not supported by device", __func__);
 292                retval = -ENODEV;
 293        } else if (!context->display_isopen) {
 294                err("%s: display is not open", __func__);
 295                retval = -EIO;
 296        } else {
 297                context->display_isopen = 0;
 298                dev_info(context->driver->dev, "display port closed\n");
 299                if (!context->dev_present && !context->ir_isopen) {
 300                        /*
 301                         * Device disconnected before close and IR port is not
 302                         * open. If IR port is open, context will be deleted by
 303                         * ir_close.
 304                         */
 305                        mutex_unlock(&context->ctx_lock);
 306                        free_imon_context(context);
 307                        return retval;
 308                }
 309        }
 310
 311        mutex_unlock(&context->ctx_lock);
 312        return retval;
 313}
 314
 315/**
 316 * Sends a packet to the device -- this function must be called
 317 * with context->ctx_lock held.
 318 */
 319static int send_packet(struct imon_context *context)
 320{
 321        unsigned int pipe;
 322        int interval = 0;
 323        int retval = 0;
 324
 325        /* Check if we need to use control or interrupt urb */
 326        pipe = usb_sndintpipe(context->usbdev,
 327                              context->tx_endpoint->bEndpointAddress);
 328        interval = context->tx_endpoint->bInterval;
 329
 330        usb_fill_int_urb(context->tx_urb, context->usbdev, pipe,
 331                         context->usb_tx_buf,
 332                         sizeof(context->usb_tx_buf),
 333                         usb_tx_callback, context, interval);
 334
 335        context->tx_urb->actual_length = 0;
 336
 337        init_completion(&context->tx.finished);
 338        atomic_set(&(context->tx.busy), 1);
 339
 340        retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
 341        if (retval) {
 342                atomic_set(&(context->tx.busy), 0);
 343                err("%s: error submitting urb(%d)", __func__, retval);
 344        } else {
 345                /* Wait for transmission to complete (or abort) */
 346                mutex_unlock(&context->ctx_lock);
 347                retval = wait_for_completion_interruptible(
 348                                &context->tx.finished);
 349                if (retval)
 350                        err("%s: task interrupted", __func__);
 351                mutex_lock(&context->ctx_lock);
 352
 353                retval = context->tx.status;
 354                if (retval)
 355                        err("%s: packet tx failed (%d)", __func__, retval);
 356        }
 357
 358        return retval;
 359}
 360
 361/**
 362 * Writes data to the VFD.  The iMON VFD is 2x16 characters
 363 * and requires data in 5 consecutive USB interrupt packets,
 364 * each packet but the last carrying 7 bytes.
 365 *
 366 * I don't know if the VFD board supports features such as
 367 * scrolling, clearing rows, blanking, etc. so at
 368 * the caller must provide a full screen of data.  If fewer
 369 * than 32 bytes are provided spaces will be appended to
 370 * generate a full screen.
 371 */
 372static ssize_t vfd_write(struct file *file, const char *buf,
 373                         size_t n_bytes, loff_t *pos)
 374{
 375        int i;
 376        int offset;
 377        int seq;
 378        int retval = 0;
 379        struct imon_context *context;
 380        const unsigned char vfd_packet6[] = {
 381                0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
 382        int *data_buf = NULL;
 383
 384        context = file->private_data;
 385        if (!context) {
 386                err("%s: no context for device", __func__);
 387                return -ENODEV;
 388        }
 389
 390        mutex_lock(&context->ctx_lock);
 391
 392        if (!context->dev_present) {
 393                err("%s: no iMON device present", __func__);
 394                retval = -ENODEV;
 395                goto exit;
 396        }
 397
 398        if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) {
 399                err("%s: invalid payload size", __func__);
 400                retval = -EINVAL;
 401                goto exit;
 402        }
 403
 404        data_buf = memdup_user(buf, n_bytes);
 405        if (IS_ERR(data_buf)) {
 406                retval = PTR_ERR(data_buf);
 407                goto exit;
 408        }
 409
 410        memcpy(context->tx.data_buf, data_buf, n_bytes);
 411
 412        /* Pad with spaces */
 413        for (i = n_bytes; i < IMON_DATA_BUF_SZ - 3; ++i)
 414                context->tx.data_buf[i] = ' ';
 415
 416        for (i = IMON_DATA_BUF_SZ - 3; i < IMON_DATA_BUF_SZ; ++i)
 417                context->tx.data_buf[i] = 0xFF;
 418
 419        offset = 0;
 420        seq = 0;
 421
 422        do {
 423                memcpy(context->usb_tx_buf, context->tx.data_buf + offset, 7);
 424                context->usb_tx_buf[7] = (unsigned char) seq;
 425
 426                retval = send_packet(context);
 427                if (retval) {
 428                        err("%s: send packet failed for packet #%d",
 429                                        __func__, seq/2);
 430                        goto exit;
 431                } else {
 432                        seq += 2;
 433                        offset += 7;
 434                }
 435
 436        } while (offset < IMON_DATA_BUF_SZ);
 437
 438        if (context->vfd_proto_6p) {
 439                /* Send packet #6 */
 440                memcpy(context->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6));
 441                context->usb_tx_buf[7] = (unsigned char) seq;
 442                retval = send_packet(context);
 443                if (retval)
 444                        err("%s: send packet failed for packet #%d",
 445                                        __func__, seq/2);
 446        }
 447
 448exit:
 449        mutex_unlock(&context->ctx_lock);
 450        kfree(data_buf);
 451
 452        return (!retval) ? n_bytes : retval;
 453}
 454
 455/**
 456 * Callback function for USB core API: transmit data
 457 */
 458static void usb_tx_callback(struct urb *urb)
 459{
 460        struct imon_context *context;
 461
 462        if (!urb)
 463                return;
 464        context = (struct imon_context *)urb->context;
 465        if (!context)
 466                return;
 467
 468        context->tx.status = urb->status;
 469
 470        /* notify waiters that write has finished */
 471        atomic_set(&context->tx.busy, 0);
 472        complete(&context->tx.finished);
 473
 474        return;
 475}
 476
 477/**
 478 * Called by lirc_dev when the application opens /dev/lirc
 479 */
 480static int ir_open(void *data)
 481{
 482        int retval = 0;
 483        struct imon_context *context;
 484
 485        /* prevent races with disconnect */
 486        mutex_lock(&driver_lock);
 487
 488        context = (struct imon_context *)data;
 489
 490        /* initial IR protocol decode variables */
 491        context->rx.count = 0;
 492        context->rx.initial_space = 1;
 493        context->rx.prev_bit = 0;
 494
 495        context->ir_isopen = 1;
 496        dev_info(context->driver->dev, "IR port opened\n");
 497
 498        mutex_unlock(&driver_lock);
 499        return retval;
 500}
 501
 502/**
 503 * Called by lirc_dev when the application closes /dev/lirc
 504 */
 505static void ir_close(void *data)
 506{
 507        struct imon_context *context;
 508
 509        context = (struct imon_context *)data;
 510        if (!context) {
 511                err("%s: no context for device", __func__);
 512                return;
 513        }
 514
 515        mutex_lock(&context->ctx_lock);
 516
 517        context->ir_isopen = 0;
 518        dev_info(context->driver->dev, "IR port closed\n");
 519
 520        if (!context->dev_present) {
 521                /*
 522                 * Device disconnected while IR port was still open. Driver
 523                 * was not deregistered at disconnect time, so do it now.
 524                 */
 525                deregister_from_lirc(context);
 526
 527                if (!context->display_isopen) {
 528                        mutex_unlock(&context->ctx_lock);
 529                        free_imon_context(context);
 530                        return;
 531                }
 532                /*
 533                 * If display port is open, context will be deleted by
 534                 * display_close
 535                 */
 536        }
 537
 538        mutex_unlock(&context->ctx_lock);
 539        return;
 540}
 541
 542/**
 543 * Convert bit count to time duration (in us) and submit
 544 * the value to lirc_dev.
 545 */
 546static void submit_data(struct imon_context *context)
 547{
 548        unsigned char buf[4];
 549        int value = context->rx.count;
 550        int i;
 551
 552        dev_dbg(context->driver->dev, "submitting data to LIRC\n");
 553
 554        value *= BIT_DURATION;
 555        value &= PULSE_MASK;
 556        if (context->rx.prev_bit)
 557                value |= PULSE_BIT;
 558
 559        for (i = 0; i < 4; ++i)
 560                buf[i] = value>>(i*8);
 561
 562        lirc_buffer_write(context->driver->rbuf, buf);
 563        wake_up(&context->driver->rbuf->wait_poll);
 564        return;
 565}
 566
 567static inline int tv2int(const struct timeval *a, const struct timeval *b)
 568{
 569        int usecs = 0;
 570        int sec   = 0;
 571
 572        if (b->tv_usec > a->tv_usec) {
 573                usecs = 1000000;
 574                sec--;
 575        }
 576
 577        usecs += a->tv_usec - b->tv_usec;
 578
 579        sec += a->tv_sec - b->tv_sec;
 580        sec *= 1000;
 581        usecs /= 1000;
 582        sec += usecs;
 583
 584        if (sec < 0)
 585                sec = 1000;
 586
 587        return sec;
 588}
 589
 590/**
 591 * Process the incoming packet
 592 */
 593static void imon_incoming_packet(struct imon_context *context,
 594                                 struct urb *urb, int intf)
 595{
 596        int len = urb->actual_length;
 597        unsigned char *buf = urb->transfer_buffer;
 598        struct device *dev = context->driver->dev;
 599        int octet, bit;
 600        unsigned char mask;
 601        int i;
 602
 603        /*
 604         * just bail out if no listening IR client
 605         */
 606        if (!context->ir_isopen)
 607                return;
 608
 609        if (len != 8) {
 610                dev_warn(dev, "imon %s: invalid incoming packet "
 611                         "size (len = %d, intf%d)\n", __func__, len, intf);
 612                return;
 613        }
 614
 615        if (debug) {
 616                printk(KERN_INFO "raw packet: ");
 617                for (i = 0; i < len; ++i)
 618                        printk("%02x ", buf[i]);
 619                printk("\n");
 620        }
 621
 622        /*
 623         * Translate received data to pulse and space lengths.
 624         * Received data is active low, i.e. pulses are 0 and
 625         * spaces are 1.
 626         *
 627         * My original algorithm was essentially similar to
 628         * Changwoo Ryu's with the exception that he switched
 629         * the incoming bits to active high and also fed an
 630         * initial space to LIRC at the start of a new sequence
 631         * if the previous bit was a pulse.
 632         *
 633         * I've decided to adopt his algorithm.
 634         */
 635
 636        if (buf[7] == 1 && context->rx.initial_space) {
 637                /* LIRC requires a leading space */
 638                context->rx.prev_bit = 0;
 639                context->rx.count = 4;
 640                submit_data(context);
 641                context->rx.count = 0;
 642        }
 643
 644        for (octet = 0; octet < 5; ++octet) {
 645                mask = 0x80;
 646                for (bit = 0; bit < 8; ++bit) {
 647                        int curr_bit = !(buf[octet] & mask);
 648                        if (curr_bit != context->rx.prev_bit) {
 649                                if (context->rx.count) {
 650                                        submit_data(context);
 651                                        context->rx.count = 0;
 652                                }
 653                                context->rx.prev_bit = curr_bit;
 654                        }
 655                        ++context->rx.count;
 656                        mask >>= 1;
 657                }
 658        }
 659
 660        if (buf[7] == 10) {
 661                if (context->rx.count) {
 662                        submit_data(context);
 663                        context->rx.count = 0;
 664                }
 665                context->rx.initial_space = context->rx.prev_bit;
 666        }
 667}
 668
 669/**
 670 * Callback function for USB core API: receive data
 671 */
 672static void usb_rx_callback(struct urb *urb)
 673{
 674        struct imon_context *context;
 675        int intfnum = 0;
 676
 677        if (!urb)
 678                return;
 679
 680        context = (struct imon_context *)urb->context;
 681        if (!context)
 682                return;
 683
 684        switch (urb->status) {
 685        case -ENOENT:           /* usbcore unlink successful! */
 686                return;
 687
 688        case 0:
 689                imon_incoming_packet(context, urb, intfnum);
 690                break;
 691
 692        default:
 693                dev_warn(context->driver->dev, "imon %s: status(%d): ignored\n",
 694                         __func__, urb->status);
 695                break;
 696        }
 697
 698        usb_submit_urb(context->rx_urb, GFP_ATOMIC);
 699
 700        return;
 701}
 702
 703/**
 704 * Callback function for USB core API: Probe
 705 */
 706static int imon_probe(struct usb_interface *interface,
 707                      const struct usb_device_id *id)
 708{
 709        struct usb_device *usbdev = NULL;
 710        struct usb_host_interface *iface_desc = NULL;
 711        struct usb_endpoint_descriptor *rx_endpoint = NULL;
 712        struct usb_endpoint_descriptor *tx_endpoint = NULL;
 713        struct urb *rx_urb = NULL;
 714        struct urb *tx_urb = NULL;
 715        struct lirc_driver *driver = NULL;
 716        struct lirc_buffer *rbuf = NULL;
 717        struct device *dev = &interface->dev;
 718        int ifnum;
 719        int lirc_minor = 0;
 720        int num_endpts;
 721        int retval = 0;
 722        int display_ep_found = 0;
 723        int ir_ep_found = 0;
 724        int alloc_status = 0;
 725        int vfd_proto_6p = 0;
 726        struct imon_context *context = NULL;
 727        int i;
 728        u16 vendor, product;
 729
 730        /* prevent races probing devices w/multiple interfaces */
 731        mutex_lock(&driver_lock);
 732
 733        context = kzalloc(sizeof(struct imon_context), GFP_KERNEL);
 734        if (!context) {
 735                err("%s: kzalloc failed for context", __func__);
 736                alloc_status = 1;
 737                goto alloc_status_switch;
 738        }
 739
 740        /*
 741         * Try to auto-detect the type of display if the user hasn't set
 742         * it by hand via the display_type modparam. Default is VFD.
 743         */
 744        if (usb_match_id(interface, ir_only_list))
 745                context->display = 0;
 746        else
 747                context->display = 1;
 748
 749        usbdev     = usb_get_dev(interface_to_usbdev(interface));
 750        iface_desc = interface->cur_altsetting;
 751        num_endpts = iface_desc->desc.bNumEndpoints;
 752        ifnum      = iface_desc->desc.bInterfaceNumber;
 753        vendor     = le16_to_cpu(usbdev->descriptor.idVendor);
 754        product    = le16_to_cpu(usbdev->descriptor.idProduct);
 755
 756        dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n",
 757                __func__, vendor, product, ifnum);
 758
 759        /*
 760         * Scan the endpoint list and set:
 761         *      first input endpoint = IR endpoint
 762         *      first output endpoint = display endpoint
 763         */
 764        for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
 765                struct usb_endpoint_descriptor *ep;
 766                int ep_dir;
 767                int ep_type;
 768                ep = &iface_desc->endpoint[i].desc;
 769                ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
 770                ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
 771
 772                if (!ir_ep_found &&
 773                        ep_dir == USB_DIR_IN &&
 774                        ep_type == USB_ENDPOINT_XFER_INT) {
 775
 776                        rx_endpoint = ep;
 777                        ir_ep_found = 1;
 778                        dev_dbg(dev, "%s: found IR endpoint\n", __func__);
 779
 780                } else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
 781                           ep_type == USB_ENDPOINT_XFER_INT) {
 782                        tx_endpoint = ep;
 783                        display_ep_found = 1;
 784                        dev_dbg(dev, "%s: found display endpoint\n", __func__);
 785                }
 786        }
 787
 788        /*
 789         * Some iMON receivers have no display. Unfortunately, it seems
 790         * that SoundGraph recycles device IDs between devices both with
 791         * and without... :\
 792         */
 793        if (context->display == 0) {
 794                display_ep_found = 0;
 795                dev_dbg(dev, "%s: device has no display\n", __func__);
 796        }
 797
 798        /* Input endpoint is mandatory */
 799        if (!ir_ep_found) {
 800                err("%s: no valid input (IR) endpoint found.", __func__);
 801                retval = -ENODEV;
 802                alloc_status = 2;
 803                goto alloc_status_switch;
 804        }
 805
 806        /* Determine if display requires 6 packets */
 807        if (display_ep_found) {
 808                if (usb_match_id(interface, vfd_proto_6p_list))
 809                        vfd_proto_6p = 1;
 810
 811                dev_dbg(dev, "%s: vfd_proto_6p: %d\n",
 812                        __func__, vfd_proto_6p);
 813        }
 814
 815        driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
 816        if (!driver) {
 817                err("%s: kzalloc failed for lirc_driver", __func__);
 818                alloc_status = 2;
 819                goto alloc_status_switch;
 820        }
 821        rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
 822        if (!rbuf) {
 823                err("%s: kmalloc failed for lirc_buffer", __func__);
 824                alloc_status = 3;
 825                goto alloc_status_switch;
 826        }
 827        if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
 828                err("%s: lirc_buffer_init failed", __func__);
 829                alloc_status = 4;
 830                goto alloc_status_switch;
 831        }
 832        rx_urb = usb_alloc_urb(0, GFP_KERNEL);
 833        if (!rx_urb) {
 834                err("%s: usb_alloc_urb failed for IR urb", __func__);
 835                alloc_status = 5;
 836                goto alloc_status_switch;
 837        }
 838        tx_urb = usb_alloc_urb(0, GFP_KERNEL);
 839        if (!tx_urb) {
 840                err("%s: usb_alloc_urb failed for display urb",
 841                    __func__);
 842                alloc_status = 6;
 843                goto alloc_status_switch;
 844        }
 845
 846        mutex_init(&context->ctx_lock);
 847        context->vfd_proto_6p = vfd_proto_6p;
 848
 849        strcpy(driver->name, MOD_NAME);
 850        driver->minor = -1;
 851        driver->code_length = BUF_CHUNK_SIZE * 8;
 852        driver->sample_rate = 0;
 853        driver->features = LIRC_CAN_REC_MODE2;
 854        driver->data = context;
 855        driver->rbuf = rbuf;
 856        driver->set_use_inc = ir_open;
 857        driver->set_use_dec = ir_close;
 858        driver->dev = &interface->dev;
 859        driver->owner = THIS_MODULE;
 860
 861        mutex_lock(&context->ctx_lock);
 862
 863        context->driver = driver;
 864        /* start out in keyboard mode */
 865
 866        lirc_minor = lirc_register_driver(driver);
 867        if (lirc_minor < 0) {
 868                err("%s: lirc_register_driver failed", __func__);
 869                alloc_status = 7;
 870                goto unlock;
 871        } else
 872                dev_info(dev, "Registered iMON driver "
 873                         "(lirc minor: %d)\n", lirc_minor);
 874
 875        /* Needed while unregistering! */
 876        driver->minor = lirc_minor;
 877
 878        context->usbdev = usbdev;
 879        context->dev_present = 1;
 880        context->rx_endpoint = rx_endpoint;
 881        context->rx_urb = rx_urb;
 882
 883        /*
 884         * tx is used to send characters to lcd/vfd, associate RF
 885         * remotes, set IR protocol, and maybe more...
 886         */
 887        context->tx_endpoint = tx_endpoint;
 888        context->tx_urb = tx_urb;
 889
 890        if (display_ep_found)
 891                context->display = 1;
 892
 893        usb_fill_int_urb(context->rx_urb, context->usbdev,
 894                usb_rcvintpipe(context->usbdev,
 895                        context->rx_endpoint->bEndpointAddress),
 896                context->usb_rx_buf, sizeof(context->usb_rx_buf),
 897                usb_rx_callback, context,
 898                context->rx_endpoint->bInterval);
 899
 900        retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
 901
 902        if (retval) {
 903                err("%s: usb_submit_urb failed for intf0 (%d)",
 904                    __func__, retval);
 905                mutex_unlock(&context->ctx_lock);
 906                goto exit;
 907        }
 908
 909        usb_set_intfdata(interface, context);
 910
 911        if (context->display && ifnum == 0) {
 912                dev_dbg(dev, "%s: Registering iMON display with sysfs\n",
 913                        __func__);
 914
 915                if (usb_register_dev(interface, &imon_class)) {
 916                        /* Not a fatal error, so ignore */
 917                        dev_info(dev, "%s: could not get a minor number for "
 918                                 "display\n", __func__);
 919                }
 920        }
 921
 922        dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
 923                 "usb<%d:%d> initialized\n", vendor, product, ifnum,
 924                 usbdev->bus->busnum, usbdev->devnum);
 925
 926unlock:
 927        mutex_unlock(&context->ctx_lock);
 928alloc_status_switch:
 929
 930        switch (alloc_status) {
 931        case 7:
 932                usb_free_urb(tx_urb);
 933        case 6:
 934                usb_free_urb(rx_urb);
 935        case 5:
 936                if (rbuf)
 937                        lirc_buffer_free(rbuf);
 938        case 4:
 939                kfree(rbuf);
 940        case 3:
 941                kfree(driver);
 942        case 2:
 943                kfree(context);
 944                context = NULL;
 945        case 1:
 946                if (retval != -ENODEV)
 947                        retval = -ENOMEM;
 948                break;
 949        case 0:
 950                retval = 0;
 951        }
 952
 953exit:
 954        mutex_unlock(&driver_lock);
 955
 956        return retval;
 957}
 958
 959/**
 960 * Callback function for USB core API: disconnect
 961 */
 962static void imon_disconnect(struct usb_interface *interface)
 963{
 964        struct imon_context *context;
 965        int ifnum;
 966
 967        /* prevent races with ir_open()/display_open() */
 968        mutex_lock(&driver_lock);
 969
 970        context = usb_get_intfdata(interface);
 971        ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
 972
 973        mutex_lock(&context->ctx_lock);
 974
 975        usb_set_intfdata(interface, NULL);
 976
 977        /* Abort ongoing write */
 978        if (atomic_read(&context->tx.busy)) {
 979                usb_kill_urb(context->tx_urb);
 980                complete_all(&context->tx.finished);
 981        }
 982
 983        context->dev_present = 0;
 984        usb_kill_urb(context->rx_urb);
 985        if (context->display)
 986                usb_deregister_dev(interface, &imon_class);
 987
 988        if (!context->ir_isopen && !context->dev_present) {
 989                deregister_from_lirc(context);
 990                mutex_unlock(&context->ctx_lock);
 991                if (!context->display_isopen)
 992                        free_imon_context(context);
 993        } else
 994                mutex_unlock(&context->ctx_lock);
 995
 996        mutex_unlock(&driver_lock);
 997
 998        printk(KERN_INFO "%s: iMON device (intf%d) disconnected\n",
 999               __func__, ifnum);
1000}
1001
1002static int imon_suspend(struct usb_interface *intf, pm_message_t message)
1003{
1004        struct imon_context *context = usb_get_intfdata(intf);
1005
1006        usb_kill_urb(context->rx_urb);
1007
1008        return 0;
1009}
1010
1011static int imon_resume(struct usb_interface *intf)
1012{
1013        int rc = 0;
1014        struct imon_context *context = usb_get_intfdata(intf);
1015
1016        usb_fill_int_urb(context->rx_urb, context->usbdev,
1017                usb_rcvintpipe(context->usbdev,
1018                        context->rx_endpoint->bEndpointAddress),
1019                context->usb_rx_buf, sizeof(context->usb_rx_buf),
1020                usb_rx_callback, context,
1021                context->rx_endpoint->bInterval);
1022
1023        rc = usb_submit_urb(context->rx_urb, GFP_ATOMIC);
1024
1025        return rc;
1026}
1027
1028static int __init imon_init(void)
1029{
1030        int rc;
1031
1032        printk(KERN_INFO MOD_NAME ": " MOD_DESC ", v" MOD_VERSION "\n");
1033
1034        rc = usb_register(&imon_driver);
1035        if (rc) {
1036                err("%s: usb register failed(%d)", __func__, rc);
1037                return -ENODEV;
1038        }
1039
1040        return 0;
1041}
1042
1043static void __exit imon_exit(void)
1044{
1045        usb_deregister(&imon_driver);
1046        printk(KERN_INFO MOD_NAME ": module removed. Goodbye!\n");
1047}
1048
1049module_init(imon_init);
1050module_exit(imon_exit);
1051
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.