Merge remote-tracking branch 'regulator/fix/core' into regulator-linus
[firefly-linux-kernel-4.4.55.git] / drivers / misc / mei / main.c
index e9513d651cd36b611920a2f6410c905b344fbf13..b2f2486b3d757cd1bba127d8328177716d539591 100644 (file)
@@ -445,6 +445,45 @@ end:
        return rets;
 }
 
+/**
+ * mei_ioctl_client_notify_request -
+ *     propagate event notification request to client
+ *
+ * @file: pointer to file structure
+ * @request: 0 - disable, 1 - enable
+ *
+ * Return: 0 on success , <0 on error
+ */
+static int mei_ioctl_client_notify_request(struct file *file, u32 request)
+{
+       struct mei_cl *cl = file->private_data;
+
+       return mei_cl_notify_request(cl, file, request);
+}
+
+/**
+ * mei_ioctl_client_notify_get -  wait for notification request
+ *
+ * @file: pointer to file structure
+ * @notify_get: 0 - disable, 1 - enable
+ *
+ * Return: 0 on success , <0 on error
+ */
+static int mei_ioctl_client_notify_get(struct file *file, u32 *notify_get)
+{
+       struct mei_cl *cl = file->private_data;
+       bool notify_ev;
+       bool block = (file->f_flags & O_NONBLOCK) == 0;
+       int rets;
+
+       rets = mei_cl_notify_get(cl, block, &notify_ev);
+       if (rets)
+               return rets;
+
+       *notify_get = notify_ev ? 1 : 0;
+       return 0;
+}
+
 /**
  * mei_ioctl - the IOCTL function
  *
@@ -459,6 +498,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
        struct mei_device *dev;
        struct mei_cl *cl = file->private_data;
        struct mei_connect_client_data connect_data;
+       u32 notify_get, notify_req;
        int rets;
 
 
@@ -499,6 +539,33 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
 
                break;
 
+       case IOCTL_MEI_NOTIFY_SET:
+               dev_dbg(dev->dev, ": IOCTL_MEI_NOTIFY_SET.\n");
+               if (copy_from_user(&notify_req,
+                                  (char __user *)data, sizeof(notify_req))) {
+                       dev_dbg(dev->dev, "failed to copy data from userland\n");
+                       rets = -EFAULT;
+                       goto out;
+               }
+               rets = mei_ioctl_client_notify_request(file, notify_req);
+               break;
+
+       case IOCTL_MEI_NOTIFY_GET:
+               dev_dbg(dev->dev, ": IOCTL_MEI_NOTIFY_GET.\n");
+               rets = mei_ioctl_client_notify_get(file, &notify_get);
+               if (rets)
+                       goto out;
+
+               dev_dbg(dev->dev, "copy connect data to user\n");
+               if (copy_to_user((char __user *)data,
+                               &notify_get, sizeof(notify_get))) {
+                       dev_dbg(dev->dev, "failed to copy data to userland\n");
+                       rets = -EFAULT;
+                       goto out;
+
+               }
+               break;
+
        default:
                dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd);
                rets = -ENOIOCTLCMD;
@@ -541,6 +608,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
        struct mei_cl *cl = file->private_data;
        struct mei_device *dev;
        unsigned int mask = 0;
+       bool notify_en;
 
        if (WARN_ON(!cl || !cl->dev))
                return POLLERR;
@@ -549,6 +617,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
 
        mutex_lock(&dev->device_lock);
 
+       notify_en = cl->notify_en && (req_events & POLLPRI);
 
        if (dev->dev_state != MEI_DEV_ENABLED ||
            !mei_cl_is_connected(cl)) {
@@ -561,6 +630,12 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
                goto out;
        }
 
+       if (notify_en) {
+               poll_wait(file, &cl->ev_wait, wait);
+               if (cl->notify_ev)
+                       mask |= POLLPRI;
+       }
+
        if (req_events & (POLLIN | POLLRDNORM)) {
                poll_wait(file, &cl->rx_wait, wait);
 
@@ -575,6 +650,26 @@ out:
        return mask;
 }
 
+/**
+ * mei_fasync - asynchronous io support
+ *
+ * @fd: file descriptor
+ * @file: pointer to file structure
+ * @band: band bitmap
+ *
+ * Return: poll mask
+ */
+static int mei_fasync(int fd, struct file *file, int band)
+{
+
+       struct mei_cl *cl = file->private_data;
+
+       if (!mei_cl_is_connected(cl))
+               return POLLERR;
+
+       return fasync_helper(fd, file, band, &cl->ev_async);
+}
+
 /**
  * fw_status_show - mei device attribute show method
  *
@@ -627,6 +722,7 @@ static const struct file_operations mei_fops = {
        .release = mei_release,
        .write = mei_write,
        .poll = mei_poll,
+       .fasync = mei_fasync,
        .llseek = no_llseek
 };