]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/staging/lirc/lirc_zilog.c
Merge branch 'for-2.6.38' of git://linux-nfs.org/~bfields/linux
[mv-sheeva.git] / drivers / staging / lirc / lirc_zilog.c
index f2e8c63fa5bd0c03bfb7cddc36f613c2dc7747b2..0aad0d7a74a3789c6a416b9391e254d01843d51c 100644 (file)
@@ -20,6 +20,9 @@
  *
  * parts are cut&pasted from the lirc_i2c.c driver
  *
+ * Numerous changes updating lirc_zilog.c in kernel 2.6.38 and later are
+ * Copyright (C) 2011 Andy Walls <awalls@md.metrocast.net>
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
@@ -69,9 +72,6 @@ struct IR_rx {
        struct mutex buf_lock;
 
        /* RX polling thread data */
-       struct completion *t_notify;
-       struct completion *t_notify2;
-       int shutdown;
        struct task_struct *task;
 
        /* RX read data */
@@ -171,12 +171,20 @@ static int add_to_buf(struct IR *ir)
         * data and we have space
         */
        do {
+               if (kthread_should_stop())
+                       return -ENODATA;
+
                /*
                 * Lock i2c bus for the duration.  RX/TX chips interfere so
                 * this is worth it
                 */
                mutex_lock(&ir->ir_lock);
 
+               if (kthread_should_stop()) {
+                       mutex_unlock(&ir->ir_lock);
+                       return -ENODATA;
+               }
+
                /*
                 * Send random "poll command" (?)  Windows driver does this
                 * and it is a good point to detect chip failure.
@@ -196,15 +204,22 @@ static int add_to_buf(struct IR *ir)
                                    "trying reset\n");
 
                        set_current_state(TASK_UNINTERRUPTIBLE);
+                       if (kthread_should_stop()) {
+                               mutex_unlock(&ir->ir_lock);
+                               return -ENODATA;
+                       }
                        schedule_timeout((100 * HZ + 999) / 1000);
-                       if (ir->tx != NULL)
-                               ir->tx->need_boot = 1;
+                       ir->tx->need_boot = 1;
 
                        ++failures;
                        mutex_unlock(&ir->ir_lock);
                        continue;
                }
 
+               if (kthread_should_stop()) {
+                       mutex_unlock(&ir->ir_lock);
+                       return -ENODATA;
+               }
                ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf));
                mutex_unlock(&ir->ir_lock);
                if (ret != sizeof(keybuf)) {
@@ -255,48 +270,35 @@ static int lirc_thread(void *arg)
        struct IR *ir = arg;
        struct IR_rx *rx = ir->rx;
 
-       if (rx->t_notify != NULL)
-               complete(rx->t_notify);
-
        dprintk("poll thread started\n");
 
-       do {
-               if (ir->open) {
-                       set_current_state(TASK_INTERRUPTIBLE);
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
 
-                       /*
-                        * This is ~113*2 + 24 + jitter (2*repeat gap +
-                        * code length).  We use this interval as the chip
-                        * resets every time you poll it (bad!).  This is
-                        * therefore just sufficient to catch all of the
-                        * button presses.  It makes the remote much more
-                        * responsive.  You can see the difference by
-                        * running irw and holding down a button.  With
-                        * 100ms, the old polling interval, you'll notice
-                        * breaks in the repeat sequence corresponding to
-                        * lost keypresses.
-                        */
-                       schedule_timeout((260 * HZ) / 1000);
-                       if (rx->shutdown)
-                               break;
-                       if (!add_to_buf(ir))
-                               wake_up_interruptible(&rx->buf.wait_poll);
-               } else {
-                       /* if device not opened so we can sleep half a second */
-                       set_current_state(TASK_INTERRUPTIBLE);
+               /* if device not opened, we can sleep half a second */
+               if (!ir->open) {
                        schedule_timeout(HZ/2);
+                       continue;
                }
-       } while (!rx->shutdown);
-
-       if (rx->t_notify2 != NULL)
-               wait_for_completion(rx->t_notify2);
 
-       rx->task = NULL;
-       if (rx->t_notify != NULL)
-               complete(rx->t_notify);
+               /*
+                * This is ~113*2 + 24 + jitter (2*repeat gap + code length).
+                * We use this interval as the chip resets every time you poll
+                * it (bad!).  This is therefore just sufficient to catch all
+                * of the button presses.  It makes the remote much more
+                * responsive.  You can see the difference by running irw and
+                * holding down a button.  With 100ms, the old polling
+                * interval, you'll notice breaks in the repeat sequence
+                * corresponding to lost keypresses.
+                */
+               schedule_timeout((260 * HZ) / 1000);
+               if (kthread_should_stop())
+                       break;
+               if (!add_to_buf(ir))
+                       wake_up_interruptible(&rx->buf.wait_poll);
+       }
 
        dprintk("poll thread ended\n");
-       /* FIXME - investigate if this is the proper way to shutdown a kthread*/
        return 0;
 }
 
@@ -493,7 +495,7 @@ static int send_data_block(struct IR_tx *tx, unsigned char *data_block)
 /* send boot data to the IR TX device */
 static int send_boot_data(struct IR_tx *tx)
 {
-       int ret;
+       int ret, i;
        unsigned char buf[4];
 
        /* send the boot block */
@@ -501,7 +503,7 @@ static int send_boot_data(struct IR_tx *tx)
        if (ret != 0)
                return ret;
 
-       /* kick it off? */
+       /* Hit the go button to activate the new boot data */
        buf[0] = 0x00;
        buf[1] = 0x20;
        ret = i2c_master_send(tx->c, buf, 2);
@@ -509,7 +511,19 @@ static int send_boot_data(struct IR_tx *tx)
                zilog_error("i2c_master_send failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
        }
-       ret = i2c_master_send(tx->c, buf, 1);
+
+       /*
+        * Wait for zilog to settle after hitting go post boot block upload.
+        * Without this delay, the HD-PVR and HVR-1950 both return an -EIO
+        * upon attempting to get firmware revision, and tx probe thus fails.
+        */
+       for (i = 0; i < 10; i++) {
+               ret = i2c_master_send(tx->c, buf, 1);
+               if (ret == 1)
+                       break;
+               udelay(100);
+       }
+
        if (ret != 1) {
                zilog_error("i2c_master_send failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
@@ -521,8 +535,8 @@ static int send_boot_data(struct IR_tx *tx)
                zilog_error("i2c_master_recv failed with %d\n", ret);
                return 0;
        }
-       if (buf[0] != 0x80) {
-               zilog_error("unexpected IR TX response: %02x\n", buf[0]);
+       if ((buf[0] != 0x80) && (buf[0] != 0xa0)) {
+               zilog_error("unexpected IR TX init response: %02x\n", buf[0]);
                return 0;
        }
        zilog_notify("Zilog/Hauppauge IR blaster firmware version "
@@ -825,7 +839,15 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
                zilog_error("i2c_master_send failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
        }
-       ret = i2c_master_send(tx->c, buf, 1);
+
+       /* Give the z8 a moment to process data block */
+       for (i = 0; i < 10; i++) {
+               ret = i2c_master_send(tx->c, buf, 1);
+               if (ret == 1)
+                       break;
+               udelay(100);
+       }
+
        if (ret != 1) {
                zilog_error("i2c_master_send failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
@@ -1010,10 +1032,9 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
        int result;
        unsigned long mode, features = 0;
 
+       features |= LIRC_CAN_SEND_PULSE;
        if (ir->rx != NULL)
                features |= LIRC_CAN_REC_LIRCCODE;
-       if (ir->tx != NULL)
-               features |= LIRC_CAN_SEND_PULSE;
 
        switch (cmd) {
        case LIRC_GET_LENGTH:
@@ -1040,15 +1061,9 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
                        result = -EINVAL;
                break;
        case LIRC_GET_SEND_MODE:
-               if (!(features&LIRC_CAN_SEND_MASK))
-                       return -ENOSYS;
-
                result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
                break;
        case LIRC_SET_SEND_MODE:
-               if (!(features&LIRC_CAN_SEND_MASK))
-                       return -ENOSYS;
-
                result = get_user(mode, (unsigned long *) arg);
                if (!result && mode != LIRC_MODE_PULSE)
                        return -EINVAL;
@@ -1131,7 +1146,6 @@ static struct lirc_driver lirc_template = {
 
 static int ir_remove(struct i2c_client *client);
 static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id);
-static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg);
 
 #define ID_FLAG_TX     0x01
 #define ID_FLAG_HDPVR  0x02
@@ -1151,7 +1165,6 @@ static struct i2c_driver driver = {
        },
        .probe          = ir_probe,
        .remove         = ir_remove,
-       .command        = ir_command,
        .id_table       = ir_transceiver_id,
 };
 
@@ -1169,25 +1182,12 @@ static const struct file_operations lirc_fops = {
        .release        = close
 };
 
-/* FIXME - investigate if this is the proper way to shutdown a kthread */
 static void destroy_rx_kthread(struct IR_rx *rx)
 {
-       DECLARE_COMPLETION(tn);
-       DECLARE_COMPLETION(tn2);
-
-       if (rx == NULL)
-               return;
-
        /* end up polling thread */
-       if (rx->task && !IS_ERR(rx->task)) {
-               rx->t_notify = &tn;
-               rx->t_notify2 = &tn2;
-               rx->shutdown = 1;
-               wake_up_process(rx->task);
-               complete(&tn2);
-               wait_for_completion(&tn);
-               rx->t_notify = NULL;
-               rx->t_notify2 = NULL;
+       if (rx != NULL && !IS_ERR_OR_NULL(rx->task)) {
+               kthread_stop(rx->task);
+               rx->task = NULL;
        }
 }
 
@@ -1290,8 +1290,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
        else if (tx_only) /* module option */
                return -ENXIO;
 
-       zilog_info("%s: probing IR %s on %s (i2c-%d)\n",
-                  __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
+       zilog_info("probing IR %s on %s (i2c-%d)\n",
+                  tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
 
        mutex_lock(&ir_devices_lock);
 
@@ -1360,27 +1360,23 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
        /* Proceed only if we have the required Tx and Rx clients ready to go */
        if (ir->tx == NULL ||
            (ir->rx == NULL && !tx_only)) {
-               zilog_info("%s: probe of IR %s on %s (i2c-%d) done, waiting on "
-                          "IR %s\n", __func__, tx_probe ? "Tx" : "Rx",
-                          adap->name, adap->nr, tx_probe ? "Rx" : "Tx");
+               zilog_info("probe of IR %s on %s (i2c-%d) done. Waiting on "
+                          "IR %s.\n", tx_probe ? "Tx" : "Rx", adap->name,
+                          adap->nr, tx_probe ? "Rx" : "Tx");
                goto out_ok;
        }
 
        /* initialise RX device */
        if (ir->rx != NULL) {
-               DECLARE_COMPLETION(tn);
-
                /* try to fire up polling thread */
-               ir->rx->t_notify = &tn;
-               ir->rx->task = kthread_run(lirc_thread, ir, "lirc_zilog");
+               ir->rx->task = kthread_run(lirc_thread, ir,
+                                          "zilog-rx-i2c-%d", adap->nr);
                if (IS_ERR(ir->rx->task)) {
                        ret = PTR_ERR(ir->rx->task);
                        zilog_error("%s: could not start IR Rx polling thread"
                                    "\n", __func__);
                        goto out_free_xx;
                }
-               wait_for_completion(&tn);
-               ir->rx->t_notify = NULL;
        }
 
        /* register with lirc */
@@ -1397,13 +1393,12 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
         * after registering with lirc as otherwise hotplug seems to take
         * 10s to create the lirc device.
         */
-       if (ir->tx != NULL) {
-               /* Special TX init */
-               ret = tx_init(ir->tx);
-               if (ret != 0)
-                       goto out_unregister;
-       }
+       ret = tx_init(ir->tx);
+       if (ret != 0)
+               goto out_unregister;
 
+       zilog_info("probe of IR %s on %s (i2c-%d) done. IR unit ready.\n",
+                  tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
 out_ok:
        mutex_unlock(&ir_devices_lock);
        return 0;
@@ -1436,12 +1431,6 @@ out_no_ir:
        return ret;
 }
 
-static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-       /* nothing */
-       return 0;
-}
-
 static int __init zilog_init(void)
 {
        int ret;
@@ -1475,7 +1464,8 @@ module_exit(zilog_exit);
 
 MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)");
 MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, "
-             "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver");
+             "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver, "
+             "Andy Walls");
 MODULE_LICENSE("GPL");
 /* for compat with old name, which isn't all that accurate anymore */
 MODULE_ALIAS("lirc_pvr150");