mei: add async event notification ioctls
authorTomas Winkler <tomas.winkler@intel.com>
Sun, 26 Jul 2015 06:54:20 +0000 (09:54 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 4 Aug 2015 00:30:00 +0000 (17:30 -0700)
Add ioctl IOCTL_MEI_NOTIFY_SET for enabling and disabling
async event notification.
Add ioctl IOCTL_MEI_NOTIFY_GET for receiving and acking
an event notification.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ioctl/ioctl-number.txt
Documentation/misc-devices/mei/mei.txt
drivers/misc/mei/main.c
include/uapi/linux/mei.h

index 611c522..141f847 100644 (file)
@@ -124,6 +124,8 @@ Code  Seq#(hex)     Include File            Comments
 'H'    00-7F   linux/hiddev.h          conflict!
 'H'    00-0F   linux/hidraw.h          conflict!
 'H'    01      linux/mei.h             conflict!
+'H'    02      linux/mei.h             conflict!
+'H'    03      linux/mei.h             conflict!
 'H'    00-0F   sound/asound.h          conflict!
 'H'    20-40   sound/asound_fm.h       conflict!
 'H'    80-8F   sound/sfnt_info.h       conflict!
index 8d47501..91c1fa3 100644 (file)
@@ -96,7 +96,7 @@ A code snippet for an application communicating with Intel AMTHI client:
 IOCTL
 =====
 
-The Intel MEI Driver supports the following IOCTL command:
+The Intel MEI Driver supports the following IOCTL commands:
        IOCTL_MEI_CONNECT_CLIENT        Connect to firmware Feature (client).
 
        usage:
@@ -125,6 +125,49 @@ The Intel MEI Driver supports the following IOCTL command:
         data that can be sent or received. (e.g. if MTU=2K, can send
         requests up to bytes 2k and received responses up to 2k bytes).
 
+       IOCTL_MEI_NOTIFY_SET: enable or disable event notifications
+
+       Usage:
+               uint32_t enable;
+               ioctl(fd, IOCTL_MEI_NOTIFY_SET, &enable);
+
+       Inputs:
+               uint32_t enable = 1;
+               or
+               uint32_t enable[disable] = 0;
+
+       Error returns:
+               EINVAL  Wrong IOCTL Number
+               ENODEV  Device  is not initialized or the client not connected
+               ENOMEM  Unable to allocate memory to client internal data.
+               EFAULT  Fatal Error (e.g. Unable to access user input data)
+               EOPNOTSUPP if the device doesn't support the feature
+
+       Notes:
+       The client must be connected in order to enable notification events
+
+
+       IOCTL_MEI_NOTIFY_GET : retrieve event
+
+       Usage:
+               uint32_t event;
+               ioctl(fd, IOCTL_MEI_NOTIFY_GET, &event);
+
+       Outputs:
+               1 - if an event is pending
+               0 - if there is no even pending
+
+       Error returns:
+               EINVAL  Wrong IOCTL Number
+               ENODEV  Device is not initialized or the client not connected
+               ENOMEM  Unable to allocate memory to client internal data.
+               EFAULT  Fatal Error (e.g. Unable to access user input data)
+               EOPNOTSUPP if the device doesn't support the feature
+
+       Notes:
+       The client must be connected and event notification has to be enabled
+       in order to receive an event
+
 
 Intel ME Applications
 =====================
index e9513d6..ffa7003 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;
index bc0d8b6..7c3b64f 100644 (file)
@@ -107,4 +107,23 @@ struct mei_connect_client_data {
        };
 };
 
+/**
+ * DOC: set and unset event notification for a connected client
+ *
+ * The IOCTL argument is 1 for enabling event notification and 0 for
+ * disabling the service
+ * Return:  -EOPNOTSUPP if the devices doesn't support the feature
+ */
+#define IOCTL_MEI_NOTIFY_SET _IOW('H', 0x02, __u32)
+
+/**
+ * DOC: retrieve notification
+ *
+ * The IOCTL output argument is 1 if an event was is pending and 0 otherwise
+ * the ioctl has to be called in order to acknowledge pending event
+ *
+ * Return:  -EOPNOTSUPP if the devices doesn't support the feature
+ */
+#define IOCTL_MEI_NOTIFY_GET _IOR('H', 0x03, __u32)
+
 #endif /* _LINUX_MEI_H  */