unsigned int *txbuf; /* buffer with values to transmit */
        ssize_t ret = -EINVAL;
        size_t count;
+       ktime_t start;
+       s64 towait;
+       unsigned int duration = 0; /* signal duration in us */
+       int i;
+
+       start = ktime_get();
 
        lirc = lirc_get_pdata(file);
        if (!lirc)
                goto out;
        }
 
-       if (dev->tx_ir)
-               ret = dev->tx_ir(dev, txbuf, count);
+       if (!dev->tx_ir) {
+               ret = -ENOSYS;
+               goto out;
+       }
+
+       ret = dev->tx_ir(dev, txbuf, (u32)n);
+       if (ret < 0)
+               goto out;
+
+       for (i = 0; i < ret; i++)
+               duration += txbuf[i];
 
-       if (ret > 0)
-               ret *= sizeof(unsigned);
+       ret *= sizeof(unsigned int);
+
+       /*
+        * The lircd gap calculation expects the write function to
+        * wait for the actual IR signal to be transmitted before
+        * returning.
+        */
+       towait = ktime_us_delta(ktime_add_us(start, duration), ktime_get());
+       if (towait > 0) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(usecs_to_jiffies(towait));
+       }
 
 out:
        kfree(txbuf);
 
        int i, ret = 0;
        int cmdcount = 0;
        unsigned char *cmdbuf; /* MCE command buffer */
-       long signal_duration = 0; /* Singnal length in us */
-       struct timeval start_time, end_time;
-
-       do_gettimeofday(&start_time);
 
        cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL);
        if (!cmdbuf)
 
        /* Generate mce packet data */
        for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
-               signal_duration += txbuf[i];
                txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
 
                do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
        /* Transmit the command to the mce device */
        mce_async_out(ir, cmdbuf, cmdcount);
 
-       /*
-        * The lircd gap calculation expects the write function to
-        * wait the time it takes for the ircommand to be sent before
-        * it returns.
-        */
-       do_gettimeofday(&end_time);
-       signal_duration -= (end_time.tv_usec - start_time.tv_usec) +
-                          (end_time.tv_sec - start_time.tv_sec) * 1000000;
-
-       /* delay with the closest number of ticks */
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(usecs_to_jiffies(signal_duration));
-
 out:
        kfree(cmdbuf);
        return ret ? ret : count;
 
 {
        struct loopback_dev *lodev = dev->priv;
        u32 rxmask;
-       unsigned total_duration = 0;
        unsigned i;
        DEFINE_IR_RAW_EVENT(rawir);
 
-       for (i = 0; i < count; i++)
-               total_duration += abs(txbuf[i]);
-
-       if (total_duration == 0) {
-               dprintk("invalid tx data, total duration zero\n");
-               return -EINVAL;
-       }
-
        if (lodev->txcarrier < lodev->rxcarriermin ||
            lodev->txcarrier > lodev->rxcarriermax) {
                dprintk("ignoring tx, carrier out of range\n");
        ir_raw_event_handle(dev);
 
 out:
-       /* Lirc expects this function to take as long as the total duration */
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(usecs_to_jiffies(total_duration));
        return count;
 }