[PATCH 08/43] misc/mei/hdcp: Get & Put for mei cl_device

Ramalingam C
2018-02-14T14:20:05Z

Interfaces to obtain and release the cl_device reference is developed.
Using these interfaces intel hdcp driver will get the reference to the
mei client devices, so that hdcp2.2 service calls can be routed to
that client device.

During registration, call back function will be registered with
mei_hdcp driver so that when the client device is removed intel
hdcp driver can be informed.

At a time only one reference is allowed in this interfaces.

Signed-off-by: Ramalingam C <ramalingam.c@intel.com>
---
drivers/misc/mei/mei_hdcp.c | 55 ++++++++++++++++++++++++++++++++++++++++++++-
drivers/misc/mei/mei_hdcp.h | 9 ++++++++
include/linux/mei_hdcp.h | 47 ++++++++++++++++++++++++++++++++++++++
3 files changed, 110 insertions(+), 1 deletion(-)
create mode 100644 include/linux/mei_hdcp.h

diff --git a/drivers/misc/mei/mei_hdcp.c b/drivers/misc/mei/mei_hdcp.c
index 25df7034cfb4..63f77800a6f7 100644
--- a/drivers/misc/mei/mei_hdcp.c
+++ b/drivers/misc/mei/mei_hdcp.c
@@ -55,18 +55,71 @@ static int mei_hdcp_probe(struct mei_cl_device *cldev,
mei_cldev_set_drvdata(cldev, &mei_hdcp);

ret = mei_cldev_enable(cldev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(&cldev->dev, "mei_cldev_enable Failed. %d\n", ret);
+ goto err;
+ }
+
+ if (mei_hdcp.notify_on_cldev_change)
+ mei_hdcp.notify_on_cldev_change(mei_hdcp.client, cldev);
+
+ return 0;
+err:
+ if (mei_hdcp.notify_on_cldev_change)
+ mei_hdcp.notify_on_cldev_change(mei_hdcp.client, NULL);

return ret;
}

static int mei_hdcp_remove(struct mei_cl_device *cldev)
{
+ struct mei_hdcp *mei_hdcp = mei_cldev_get_drvdata(cldev);
+
+ if (mei_hdcp->notify_on_cldev_change)
+ mei_hdcp->notify_on_cldev_change(mei_hdcp->client, NULL);
+
mei_cldev_disable(cldev);
+
return 0;
}

+int mei_hdcp_cldev_get_reference(void *client_data,
+ struct mei_cl_device **cldev,
+ void (*notify_change)(void *client,
+ struct mei_cl_device
+ *cldev))
+{
+ if (!notify_change || !client_data)
+ return -EINVAL;
+
+ if (mei_hdcp.ref_cnt)
+ return -EBUSY;
+
+ if (!mei_cldev_active_and_enabled(mei_hdcp.cldev)) {
+ if (!notify_change)
+ return -EAGAIN;
+ } else {
+ *cldev = mei_hdcp.cldev;
+ }
+
+ mei_hdcp.ref_cnt++;
+ mei_hdcp.client = client_data;
+ mei_hdcp.notify_on_cldev_change = notify_change;
+
+ return 0;
+}
+EXPORT_SYMBOL(mei_hdcp_cldev_get_reference);
+
+void mei_hdcp_cldev_put_reference(struct mei_cl_device *cldev)
+{
+ if (cldev == mei_hdcp.cldev) {
+ mei_hdcp.ref_cnt--;
+ mei_hdcp.client = NULL;
+ mei_hdcp.notify_on_cldev_change = NULL;
+ }
+}
+EXPORT_SYMBOL(mei_hdcp_cldev_put_reference);
+
#define WIDI_HECI_CLIENT_GUID UUID_LE(0xB638AB7E, 0x94E2, 0x4EA2, 0xA5, \
0x52, 0xD1, 0xC5, 0x4B, \
0x62, 0x7F, 0x04)
diff --git a/drivers/misc/mei/mei_hdcp.h b/drivers/misc/mei/mei_hdcp.h
index c06c0d767c4f..7d792b5ad703 100644
--- a/drivers/misc/mei/mei_hdcp.h
+++ b/drivers/misc/mei/mei_hdcp.h
@@ -27,6 +27,15 @@

struct mei_hdcp {
struct mei_cl_device *cldev;
+
+ /* Reference to the HDCP2.2 service consumer */
+ void *client;
+
+ /* Callback function for the consumer on cl_device state change */
+ void (*notify_on_cldev_change)(void *client,
+ struct mei_cl_device *cldev);
+
+ int ref_cnt;
};

#endif /* __MEI_HDCP_H__ */
diff --git a/include/linux/mei_hdcp.h b/include/linux/mei_hdcp.h
new file mode 100644
index 000000000000..774b26da0c26
--- /dev/null
+++ b/include/linux/mei_hdcp.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _LINUX_MEI_HDCP_H
+#define _LINUX_MEI_HDCP_H
+
+#ifdef CONFIG_INTEL_MEI_HDCP
+int mei_hdcp_cldev_get_reference(void *client_data,
+ struct mei_cl_device **cldev,
+ void (*notify_change)(void *client,
+ struct mei_cl_device
+ *cldev));
+void mei_hdcp_cldev_put_reference(struct mei_cl_device *cldev);
+#else
+static inline
+int mei_hdcp_cldev_get_reference(void *client_data,
+ struct mei_cl_device **cldev,
+ void (*notify_change)(void *client,
+ struct mei_cl_device
+ *cldev))
+{
+ return -ENODEV;
+}
+static inline
+void mei_hdcp_cldev_put_reference(struct mei_cl_device *cldev)
+{}
+#endif /* defined (CONFIG_INTEL_MEI_HDCP) */
+#endif /* defined (_LINUX_MEI_HDCP_H) */