[PATCH v10 36/40] misc/mei/hdcp: Component framework for I915 Interface

Ramalingam C ramalingam.c at intel.com
Thu Jan 10 10:50:27 UTC 2019


Mei hdcp driver is designed as component slave for the I915 component
master.

v2: Rebased.
v3:
  Notifier chain is adopted for cldev state update [Tomas]
v4:
  Made static dummy functions as inline in mei_hdcp.h
  API for polling client device status
  IS_ENABLED used in header, for config status for mei_hdcp.
v5:
  Replacing the notifier with component framework. [Daniel]
v6:
  Rebased on the I915 comp master redesign.
v7:
  mei_hdcp_component_registered is made static [Uma]
  Need for global static variable mei_cldev is removed.
v8:
  comp_del only on module_unload
  master_comp->mei_dev is removed at driver->remove()
  mutex is added for the comp add, del and ops.

Signed-off-by: Ramalingam C <ramalingam.c at intel.com>
Reviewed-by: Uma Shankar <uma.shankar at intel.com>
---
 drivers/misc/mei/hdcp/mei_hdcp.c | 173 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 168 insertions(+), 5 deletions(-)

diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c
index 2807cf5767b7..985da4c2b008 100644
--- a/drivers/misc/mei/hdcp/mei_hdcp.c
+++ b/drivers/misc/mei/hdcp/mei_hdcp.c
@@ -23,11 +23,24 @@
 #include <linux/slab.h>
 #include <linux/uuid.h>
 #include <linux/mei_cl_bus.h>
+#include <linux/component.h>
 #include <drm/drm_connector.h>
 #include <drm/i915_component.h>
 
 #include "mei_hdcp.h"
 
+static struct {
+	struct i915_component_master *master_comp;
+
+	/*
+	 * Mutex to protect the component addition, deletion, master_comp update
+	 * and usage.
+	 */
+	struct mutex mutex;
+	bool comp_registered;
+	struct device *orig_dev;
+} mei_data;
+
 /**
  * mei_initiate_hdcp2_session() - Initiate a Wired HDCP2.2 Tx Session in ME FW
  * @dev: device corresponding to the mei_cl_device
@@ -49,6 +62,7 @@ mei_initiate_hdcp2_session(struct device *dev, struct hdcp_port_data *data,
 	if (!dev || !data || !ake_data)
 		return -EINVAL;
 
+	mutex_lock(&mei_data.mutex);
 	cldev = to_mei_cl_device(dev);
 
 	session_init_in.header.api_version = HDCP_API_VERSION;
@@ -65,6 +79,7 @@ mei_initiate_hdcp2_session(struct device *dev, struct hdcp_port_data *data,
 			      sizeof(session_init_in));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -72,6 +87,7 @@ mei_initiate_hdcp2_session(struct device *dev, struct hdcp_port_data *data,
 			      sizeof(session_init_out));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -79,12 +95,14 @@ mei_initiate_hdcp2_session(struct device *dev, struct hdcp_port_data *data,
 		dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n",
 			WIRED_INITIATE_HDCP2_SESSION,
 			session_init_out.header.status);
+		mutex_unlock(&mei_data.mutex);
 		return -EIO;
 	}
 
 	ake_data->msg_id = HDCP_2_2_AKE_INIT;
 	ake_data->tx_caps = session_init_out.tx_caps;
 	memcpy(ake_data->r_tx, session_init_out.r_tx, HDCP_2_2_RTX_LEN);
+	mutex_unlock(&mei_data.mutex);
 
 	return 0;
 }
@@ -117,6 +135,7 @@ mei_verify_receiver_cert_prepare_km(struct device *dev,
 	if (!dev || !data || !rx_cert || !km_stored || !ek_pub_km || !msg_sz)
 		return -EINVAL;
 
+	mutex_lock(&mei_data.mutex);
 	cldev = to_mei_cl_device(dev);
 
 	verify_rxcert_in.header.api_version = HDCP_API_VERSION;
@@ -136,6 +155,7 @@ mei_verify_receiver_cert_prepare_km(struct device *dev,
 			      sizeof(verify_rxcert_in));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_send failed: %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -143,6 +163,7 @@ mei_verify_receiver_cert_prepare_km(struct device *dev,
 			      sizeof(verify_rxcert_out));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_recv failed: %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -150,6 +171,7 @@ mei_verify_receiver_cert_prepare_km(struct device *dev,
 		dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n",
 			WIRED_VERIFY_RECEIVER_CERT,
 			verify_rxcert_out.header.status);
+		mutex_unlock(&mei_data.mutex);
 		return -EIO;
 	}
 
@@ -164,6 +186,7 @@ mei_verify_receiver_cert_prepare_km(struct device *dev,
 
 	memcpy(ek_pub_km->e_kpub_km, &verify_rxcert_out.ekm_buff,
 	       sizeof(verify_rxcert_out.ekm_buff));
+	mutex_unlock(&mei_data.mutex);
 
 	return 0;
 }
@@ -187,6 +210,7 @@ static int mei_verify_hprime(struct device *dev, struct hdcp_port_data *data,
 	if (!dev || !data || !rx_hprime)
 		return -EINVAL;
 
+	mutex_lock(&mei_data.mutex);
 	cldev = to_mei_cl_device(dev);
 
 	send_hprime_in.header.api_version = HDCP_API_VERSION;
@@ -204,6 +228,7 @@ static int mei_verify_hprime(struct device *dev, struct hdcp_port_data *data,
 			      sizeof(send_hprime_in));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -211,14 +236,17 @@ static int mei_verify_hprime(struct device *dev, struct hdcp_port_data *data,
 			      sizeof(send_hprime_out));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
 	if (send_hprime_out.header.status != ME_HDCP_STATUS_SUCCESS) {
 		dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n",
 			WIRED_AKE_SEND_HPRIME, send_hprime_out.header.status);
+		mutex_unlock(&mei_data.mutex);
 		return -EIO;
 	}
+	mutex_unlock(&mei_data.mutex);
 
 	return 0;
 }
@@ -243,6 +271,7 @@ mei_store_pairing_info(struct device *dev, struct hdcp_port_data *data,
 	if (!dev || !data || !pairing_info)
 		return -EINVAL;
 
+	mutex_lock(&mei_data.mutex);
 	cldev = to_mei_cl_device(dev);
 
 	pairing_info_in.header.api_version = HDCP_API_VERSION;
@@ -261,6 +290,7 @@ mei_store_pairing_info(struct device *dev, struct hdcp_port_data *data,
 			      sizeof(pairing_info_in));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -268,6 +298,7 @@ mei_store_pairing_info(struct device *dev, struct hdcp_port_data *data,
 			      sizeof(pairing_info_out));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -275,8 +306,10 @@ mei_store_pairing_info(struct device *dev, struct hdcp_port_data *data,
 		dev_dbg(dev, "ME cmd 0x%08X failed. Status: 0x%X\n",
 			WIRED_AKE_SEND_PAIRING_INFO,
 			pairing_info_out.header.status);
+		mutex_unlock(&mei_data.mutex);
 		return -EIO;
 	}
+	mutex_unlock(&mei_data.mutex);
 
 	return 0;
 }
@@ -301,6 +334,7 @@ mei_initiate_locality_check(struct device *dev, struct hdcp_port_data *data,
 	if (!dev || !data || !lc_init_data)
 		return -EINVAL;
 
+	mutex_lock(&mei_data.mutex);
 	cldev = to_mei_cl_device(dev);
 
 	lc_init_in.header.api_version = HDCP_API_VERSION;
@@ -314,23 +348,27 @@ mei_initiate_locality_check(struct device *dev, struct hdcp_port_data *data,
 	byte = mei_cldev_send(cldev, (u8 *)&lc_init_in, sizeof(lc_init_in));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
 	byte = mei_cldev_recv(cldev, (u8 *)&lc_init_out, sizeof(lc_init_out));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
 	if (lc_init_out.header.status != ME_HDCP_STATUS_SUCCESS) {
 		dev_dbg(dev, "ME cmd 0x%08X Failed. status: 0x%X\n",
 			WIRED_INIT_LOCALITY_CHECK, lc_init_out.header.status);
+		mutex_unlock(&mei_data.mutex);
 		return -EIO;
 	}
 
 	lc_init_data->msg_id = HDCP_2_2_LC_INIT;
 	memcpy(lc_init_data->r_n, lc_init_out.r_n, HDCP_2_2_RN_LEN);
+	mutex_unlock(&mei_data.mutex);
 
 	return 0;
 }
@@ -354,6 +392,7 @@ static int mei_verify_lprime(struct device *dev, struct hdcp_port_data *data,
 	if (!dev || !data || !rx_lprime)
 		return -EINVAL;
 
+	mutex_lock(&mei_data.mutex);
 	cldev = to_mei_cl_device(dev);
 
 	verify_lprime_in.header.api_version = HDCP_API_VERSION;
@@ -372,6 +411,7 @@ static int mei_verify_lprime(struct device *dev, struct hdcp_port_data *data,
 			      sizeof(verify_lprime_in));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -379,6 +419,7 @@ static int mei_verify_lprime(struct device *dev, struct hdcp_port_data *data,
 			      sizeof(verify_lprime_out));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -386,8 +427,10 @@ static int mei_verify_lprime(struct device *dev, struct hdcp_port_data *data,
 		dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
 			WIRED_VALIDATE_LOCALITY,
 			verify_lprime_out.header.status);
+		mutex_unlock(&mei_data.mutex);
 		return -EIO;
 	}
+	mutex_unlock(&mei_data.mutex);
 
 	return 0;
 }
@@ -411,6 +454,7 @@ static int mei_get_session_key(struct device *dev, struct hdcp_port_data *data,
 	if (!dev || !data || !ske_data)
 		return -EINVAL;
 
+	mutex_lock(&mei_data.mutex);
 	cldev = to_mei_cl_device(dev);
 
 	get_skey_in.header.api_version = HDCP_API_VERSION;
@@ -424,6 +468,7 @@ static int mei_get_session_key(struct device *dev, struct hdcp_port_data *data,
 	byte = mei_cldev_send(cldev, (u8 *)&get_skey_in, sizeof(get_skey_in));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -431,12 +476,14 @@ static int mei_get_session_key(struct device *dev, struct hdcp_port_data *data,
 
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
 	if (get_skey_out.header.status != ME_HDCP_STATUS_SUCCESS) {
 		dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
 			WIRED_GET_SESSION_KEY, get_skey_out.header.status);
+		mutex_unlock(&mei_data.mutex);
 		return -EIO;
 	}
 
@@ -444,6 +491,7 @@ static int mei_get_session_key(struct device *dev, struct hdcp_port_data *data,
 	memcpy(ske_data->e_dkey_ks, get_skey_out.e_dkey_ks,
 	       HDCP_2_2_E_DKEY_KS_LEN);
 	memcpy(ske_data->riv, get_skey_out.r_iv, HDCP_2_2_RIV_LEN);
+	mutex_unlock(&mei_data.mutex);
 
 	return 0;
 }
@@ -473,6 +521,7 @@ mei_repeater_check_flow_prepare_ack(struct device *dev,
 	if (!dev || !rep_topology || !rep_send_ack || !data)
 		return -EINVAL;
 
+	mutex_lock(&mei_data.mutex);
 	cldev = to_mei_cl_device(dev);
 
 	verify_repeater_in.header.api_version = HDCP_API_VERSION;
@@ -498,6 +547,7 @@ mei_repeater_check_flow_prepare_ack(struct device *dev,
 			      sizeof(verify_repeater_in));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -505,6 +555,7 @@ mei_repeater_check_flow_prepare_ack(struct device *dev,
 			      sizeof(verify_repeater_out));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -512,12 +563,14 @@ mei_repeater_check_flow_prepare_ack(struct device *dev,
 		dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
 			WIRED_VERIFY_REPEATER,
 			verify_repeater_out.header.status);
+		mutex_unlock(&mei_data.mutex);
 		return -EIO;
 	}
 
 	memcpy(rep_send_ack->v, verify_repeater_out.v,
 	       HDCP_2_2_V_PRIME_HALF_LEN);
 	rep_send_ack->msg_id = HDCP_2_2_REP_SEND_ACK;
+	mutex_unlock(&mei_data.mutex);
 
 	return 0;
 }
@@ -543,6 +596,7 @@ static int mei_verify_mprime(struct device *dev, struct hdcp_port_data *data,
 	if (!dev || !stream_ready || !data)
 		return -EINVAL;
 
+	mutex_lock(&mei_data.mutex);
 	cldev = to_mei_cl_device(dev);
 
 	verify_mprime_in.header.api_version = HDCP_API_VERSION;
@@ -566,6 +620,7 @@ static int mei_verify_mprime(struct device *dev, struct hdcp_port_data *data,
 			      sizeof(verify_mprime_in));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -573,6 +628,7 @@ static int mei_verify_mprime(struct device *dev, struct hdcp_port_data *data,
 			      sizeof(verify_mprime_out));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -580,8 +636,10 @@ static int mei_verify_mprime(struct device *dev, struct hdcp_port_data *data,
 		dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
 			WIRED_REPEATER_AUTH_STREAM_REQ,
 			verify_mprime_out.header.status);
+		mutex_unlock(&mei_data.mutex);
 		return -EIO;
 	}
+	mutex_unlock(&mei_data.mutex);
 
 	return 0;
 }
@@ -604,6 +662,7 @@ mei_enable_hdcp_authentication(struct device *dev, struct hdcp_port_data *data)
 	if (!dev || !data)
 		return -EINVAL;
 
+	mutex_lock(&mei_data.mutex);
 	cldev = to_mei_cl_device(dev);
 
 	enable_auth_in.header.api_version = HDCP_API_VERSION;
@@ -619,6 +678,7 @@ mei_enable_hdcp_authentication(struct device *dev, struct hdcp_port_data *data)
 			      sizeof(enable_auth_in));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -626,14 +686,17 @@ mei_enable_hdcp_authentication(struct device *dev, struct hdcp_port_data *data)
 			      sizeof(enable_auth_out));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
 	if (enable_auth_out.header.status != ME_HDCP_STATUS_SUCCESS) {
 		dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
 			WIRED_ENABLE_AUTH, enable_auth_out.header.status);
+		mutex_unlock(&mei_data.mutex);
 		return -EIO;
 	}
+	mutex_unlock(&mei_data.mutex);
 
 	return 0;
 }
@@ -657,6 +720,7 @@ mei_close_hdcp_session(struct device *dev, struct hdcp_port_data *data)
 	if (!dev || !data)
 		return -EINVAL;
 
+	mutex_lock(&mei_data.mutex);
 	cldev = to_mei_cl_device(dev);
 
 	session_close_in.header.api_version = HDCP_API_VERSION;
@@ -672,6 +736,7 @@ mei_close_hdcp_session(struct device *dev, struct hdcp_port_data *data)
 			      sizeof(session_close_in));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
@@ -679,20 +744,22 @@ mei_close_hdcp_session(struct device *dev, struct hdcp_port_data *data)
 			      sizeof(session_close_out));
 	if (byte < 0) {
 		dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+		mutex_unlock(&mei_data.mutex);
 		return byte;
 	}
 
 	if (session_close_out.header.status != ME_HDCP_STATUS_SUCCESS) {
 		dev_dbg(dev, "Session Close Failed. status: 0x%X\n",
 			session_close_out.header.status);
+		mutex_unlock(&mei_data.mutex);
 		return -EIO;
 	}
+	mutex_unlock(&mei_data.mutex);
 
 	return 0;
 }
 
-static __attribute__((unused))
-struct i915_hdcp_component_ops mei_hdcp_ops = {
+static struct i915_hdcp_component_ops mei_hdcp_ops = {
 	.owner = THIS_MODULE,
 	.initiate_hdcp2_session = mei_initiate_hdcp2_session,
 	.verify_receiver_cert_prepare_km = mei_verify_receiver_cert_prepare_km,
@@ -707,20 +774,98 @@ struct i915_hdcp_component_ops mei_hdcp_ops = {
 	.close_hdcp_session = mei_close_hdcp_session,
 };
 
+static int mei_hdcp_component_bind(struct device *mei_kdev,
+				   struct device *i915_kdev, void *data)
+{
+	struct i915_component_master *master_comp = data;
+
+	dev_info(mei_kdev, "MEI HDCP comp bind\n");
+	WARN_ON(master_comp->hdcp_ops);
+	master_comp->hdcp_ops = &mei_hdcp_ops;
+	master_comp->mei_dev = mei_kdev;
+
+	mei_data.master_comp = master_comp;
+
+	return 0;
+}
+
+static void mei_hdcp_component_unbind(struct device *mei_kdev,
+				      struct device *i915_kdev, void *data)
+{
+	struct i915_component_master *master_comp = data;
+
+	if (!WARN_ON(!mei_kdev))
+		dev_info(mei_kdev, "MEI HDCP comp unbind\n");
+	master_comp->hdcp_ops = NULL;
+	master_comp->mei_dev = NULL;
+	mei_data.master_comp = NULL;
+}
+
+static const struct component_ops mei_hdcp_component_bind_ops = {
+	.bind	= mei_hdcp_component_bind,
+	.unbind	= mei_hdcp_component_unbind,
+};
+
+static void mei_hdcp_component_init(struct device *dev)
+{
+	int ret;
+
+	mutex_lock(&mei_data.mutex);
+	if (mei_data.comp_registered && mei_data.master_comp) {
+
+		/*
+		 * Component binding is not broken at driver->remove.
+		 * So at next driver probe, we need to update the dev ptr.
+		 */
+		mei_data.master_comp->mei_dev = dev;
+		mutex_unlock(&mei_data.mutex);
+		return;
+	}
+
+	dev_info(dev, "MEI HDCP comp init\n");
+	ret = component_add(dev, &mei_hdcp_component_bind_ops);
+	if (ret < 0) {
+		dev_err(dev, "Failed to add MEI HDCP comp (%d)\n", ret);
+		mutex_unlock(&mei_data.mutex);
+		return;
+	}
+
+	mei_data.comp_registered = true;
+	mei_data.orig_dev = dev;
+	mutex_unlock(&mei_data.mutex);
+}
+
+static void mei_hdcp_component_cleanup(struct device *dev)
+{
+	WARN_ON(!mutex_is_locked(&mei_data.mutex));
+
+	dev_info(dev, "MEI HDCP comp cleanup\n");
+	component_del(dev, &mei_hdcp_component_bind_ops);
+	mei_data.comp_registered = false;
+}
+
 static int mei_hdcp_probe(struct mei_cl_device *cldev,
 			  const struct mei_cl_device_id *id)
 {
 	int ret;
 
 	ret = mei_cldev_enable(cldev);
-	if (ret < 0)
+	if (ret < 0) {
 		dev_err(&cldev->dev, "mei_cldev_enable Failed. %d\n", ret);
+		return ret;
+	}
+	mei_hdcp_component_init(&cldev->dev);
 
-	return ret;
+	return 0;
 }
 
 static int mei_hdcp_remove(struct mei_cl_device *cldev)
 {
+	mutex_lock(&mei_data.mutex);
+	if (mei_data.master_comp)
+		mei_data.master_comp->mei_dev = NULL;
+	mutex_unlock(&mei_data.mutex);
+
 	return mei_cldev_disable(cldev);
 }
 
@@ -741,7 +886,25 @@ static struct mei_cl_driver mei_hdcp_driver = {
 	.remove		= mei_hdcp_remove,
 };
 
-module_mei_cl_driver(mei_hdcp_driver);
+static int __init mei_hdcp_init(void)
+{
+	mutex_init(&mei_data.mutex);
+	return mei_cldev_driver_register(&mei_hdcp_driver);
+}
+
+static void __exit mei_hdcp_exit(void)
+{
+	mutex_lock(&mei_data.mutex);
+	if (mei_data.comp_registered)
+		mei_hdcp_component_cleanup(mei_data.orig_dev);
+	mutex_unlock(&mei_data.mutex);
+
+	mei_cldev_driver_unregister(&mei_hdcp_driver);
+	mutex_destroy(&mei_data.mutex);
+}
+
+module_init(mei_hdcp_init);
+module_exit(mei_hdcp_exit);
 
 MODULE_AUTHOR("Intel Corporation");
 MODULE_LICENSE("Dual BSD/GPL");
-- 
2.7.4



More information about the Intel-gfx-trybot mailing list