wake_up_poll(&dev->wait_poll, POLLIN | POLLRDNORM);
 }
 
+/**
+ * ir_lirc_scancode_event() - Send scancode data to lirc to be relayed to
+ *             userspace
+ * @dev:       the struct rc_dev descriptor of the device
+ * @lsc:       the struct lirc_scancode describing the decoded scancode
+ */
+void ir_lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc)
+{
+       lsc->timestamp = ktime_get_ns();
+
+       if (kfifo_put(&dev->scancodes, *lsc))
+               wake_up_poll(&dev->wait_poll, POLLIN | POLLRDNORM);
+}
+EXPORT_SYMBOL_GPL(ir_lirc_scancode_event);
+
 static int ir_lirc_open(struct inode *inode, struct file *file)
 {
        struct rc_dev *dev = container_of(inode->i_cdev, struct rc_dev,
 
        if (dev->driver_type == RC_DRIVER_IR_RAW)
                kfifo_reset_out(&dev->rawir);
+       if (dev->driver_type != RC_DRIVER_IR_RAW_TX)
+               kfifo_reset_out(&dev->scancodes);
 
        dev->lirc_open++;
        file->private_data = dev;
        switch (cmd) {
        case LIRC_GET_FEATURES:
                if (dev->driver_type == RC_DRIVER_IR_RAW) {
-                       val |= LIRC_CAN_REC_MODE2;
+                       val |= LIRC_CAN_REC_MODE2 | LIRC_CAN_REC_SCANCODE;
                        if (dev->rx_resolution)
                                val |= LIRC_CAN_GET_REC_RESOLUTION;
                }
                if (dev->driver_type == RC_DRIVER_IR_RAW_TX)
                        return -ENOTTY;
 
-               val = LIRC_MODE_MODE2;
+               val = dev->rec_mode;
                break;
 
        case LIRC_SET_REC_MODE:
                if (dev->driver_type == RC_DRIVER_IR_RAW_TX)
                        return -ENOTTY;
 
-               if (val != LIRC_MODE_MODE2)
+               if (!(val == LIRC_MODE_MODE2 || val == LIRC_MODE_SCANCODE))
                        return -EINVAL;
+
+               dev->rec_mode = val;
                return 0;
 
        case LIRC_GET_SEND_MODE:
 
        poll_wait(file, &rcdev->wait_poll, wait);
 
-       if (!rcdev->registered)
+       if (!rcdev->registered) {
                events = POLLHUP | POLLERR;
-       else if (rcdev->driver_type == RC_DRIVER_IR_RAW &&
-                !kfifo_is_empty(&rcdev->rawir))
-               events = POLLIN | POLLRDNORM;
+       } else if (rcdev->driver_type != RC_DRIVER_IR_RAW_TX) {
+               if (rcdev->rec_mode == LIRC_MODE_SCANCODE &&
+                   !kfifo_is_empty(&rcdev->scancodes))
+                       events = POLLIN | POLLRDNORM;
+
+               if (rcdev->rec_mode == LIRC_MODE_MODE2 &&
+                   !kfifo_is_empty(&rcdev->rawir))
+                       events = POLLIN | POLLRDNORM;
+       }
 
        return events;
 }
 
-static ssize_t ir_lirc_read(struct file *file, char __user *buffer,
-                           size_t length, loff_t *ppos)
+static ssize_t ir_lirc_read_mode2(struct file *file, char __user *buffer,
+                                 size_t length)
 {
        struct rc_dev *rcdev = file->private_data;
        unsigned int copied;
        int ret;
 
-       if (rcdev->driver_type == RC_DRIVER_IR_RAW_TX)
-               return -EINVAL;
-
        if (length < sizeof(unsigned int) || length % sizeof(unsigned int))
                return -EINVAL;
 
-       if (!rcdev->registered)
-               return -ENODEV;
-
        do {
                if (kfifo_is_empty(&rcdev->rawir)) {
                        if (file->f_flags & O_NONBLOCK)
        return copied;
 }
 
+static ssize_t ir_lirc_read_scancode(struct file *file, char __user *buffer,
+                                    size_t length)
+{
+       struct rc_dev *rcdev = file->private_data;
+       unsigned int copied;
+       int ret;
+
+       if (length < sizeof(struct lirc_scancode) ||
+           length % sizeof(struct lirc_scancode))
+               return -EINVAL;
+
+       do {
+               if (kfifo_is_empty(&rcdev->scancodes)) {
+                       if (file->f_flags & O_NONBLOCK)
+                               return -EAGAIN;
+
+                       ret = wait_event_interruptible(rcdev->wait_poll,
+                                       !kfifo_is_empty(&rcdev->scancodes) ||
+                                       !rcdev->registered);
+                       if (ret)
+                               return ret;
+               }
+
+               if (!rcdev->registered)
+                       return -ENODEV;
+
+               ret = mutex_lock_interruptible(&rcdev->lock);
+               if (ret)
+                       return ret;
+               ret = kfifo_to_user(&rcdev->scancodes, buffer, length, &copied);
+               mutex_unlock(&rcdev->lock);
+               if (ret)
+                       return ret;
+       } while (copied == 0);
+
+       return copied;
+}
+
+static ssize_t ir_lirc_read(struct file *file, char __user *buffer,
+                           size_t length, loff_t *ppos)
+{
+       struct rc_dev *rcdev = file->private_data;
+
+       if (rcdev->driver_type == RC_DRIVER_IR_RAW_TX)
+               return -EINVAL;
+
+       if (!rcdev->registered)
+               return -ENODEV;
+
+       if (rcdev->rec_mode == LIRC_MODE_MODE2)
+               return ir_lirc_read_mode2(file, buffer, length);
+       else /* LIRC_MODE_SCANCODE */
+               return ir_lirc_read_scancode(file, buffer, length);
+}
+
 const struct file_operations lirc_fops = {
        .owner          = THIS_MODULE,
        .write          = ir_lirc_transmit_ir,
 
        struct mce_kbd_dec *data = &dev->raw->mce_kbd;
        u32 scancode;
        unsigned long delay;
+       struct lirc_scancode lsc = {};
 
        if (!is_timing_event(ev)) {
                if (ev.reset)
                        mod_timer(&data->rx_timeout, jiffies + delay);
                        /* Pass data to keyboard buffer parser */
                        ir_mce_kbd_process_keyboard_data(data->idev, scancode);
+                       lsc.rc_proto = RC_PROTO_MCIR2_KBD;
                        break;
                case MCIR2_MOUSE_NBITS:
                        scancode = data->body & 0x1fffff;
                        IR_dprintk(1, "mouse data 0x%06x\n", scancode);
                        /* Pass data to mouse buffer parser */
                        ir_mce_kbd_process_mouse_data(data->idev, scancode);
+                       lsc.rc_proto = RC_PROTO_MCIR2_MSE;
                        break;
                default:
                        IR_dprintk(1, "not keyboard or mouse data\n");
                        goto out;
                }
 
+               lsc.scancode = scancode;
+               ir_lirc_scancode_event(dev, &lsc);
                data->state = STATE_INACTIVE;
                input_event(data->idev, EV_MSC, MSC_SCAN, scancode);
                input_sync(data->idev);
 
 
        if (rcdev->driver_type == RC_DRIVER_IR_RAW)
                kfifo_free(&rcdev->rawir);
+       if (rcdev->driver_type != RC_DRIVER_IR_RAW_TX)
+               kfifo_free(&rcdev->scancodes);
 
        put_device(&rcdev->dev);
 }
        dev->lirc_dev.release = lirc_release_device;
        dev->send_mode = LIRC_MODE_PULSE;
 
+       dev->rec_mode = LIRC_MODE_MODE2;
+
        if (dev->driver_type == RC_DRIVER_IR_RAW) {
                if (kfifo_alloc(&dev->rawir, MAX_IR_EVENT_SIZE, GFP_KERNEL))
                        return -ENOMEM;
        }
 
+       if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
+               if (kfifo_alloc(&dev->scancodes, 32, GFP_KERNEL)) {
+                       kfifo_free(&dev->rawir);
+                       return -ENOMEM;
+               }
+       }
+
        init_waitqueue_head(&dev->wait_poll);
 
        minor = ida_simple_get(&lirc_ida, 0, RC_DEV_MAX, GFP_KERNEL);
 out_kfifo:
        if (dev->driver_type == RC_DRIVER_IR_RAW)
                kfifo_free(&dev->rawir);
+       if (dev->driver_type != RC_DRIVER_IR_RAW_TX)
+               kfifo_free(&dev->scancodes);
        return err;
 }
 
 
  * @gap: true if we're in a gap
  * @send_timeout_reports: report timeouts in lirc raw IR.
  * @rawir: queue for incoming raw IR
+ * @scancodes: queue for incoming decoded scancodes
  * @wait_poll: poll struct for lirc device
  * @send_mode: lirc mode for sending, either LIRC_MODE_SCANCODE or
  *     LIRC_MODE_PULSE
+ * @rec_mode: lirc mode for receiving, either LIRC_MODE_SCANCODE or
+ *     LIRC_MODE_MODE2
  * @registered: set to true by rc_register_device(), false by
  *     rc_unregister_device
  * @change_protocol: allow changing the protocol used on hardware decoders
        bool                            gap;
        bool                            send_timeout_reports;
        DECLARE_KFIFO_PTR(rawir, unsigned int);
+       DECLARE_KFIFO_PTR(scancodes, struct lirc_scancode);
        wait_queue_head_t               wait_poll;
        u8                              send_mode;
+       u8                              rec_mode;
 #endif
        bool                            registered;
        int                             (*change_protocol)(struct rc_dev *dev, u64 *rc_proto);