diff options
| author | Abhinav Kumar <abhinavk@codeaurora.org> | 2017-05-12 00:44:56 -0700 |
|---|---|---|
| committer | Abhinav Kumar <abhinavk@codeaurora.org> | 2017-06-15 21:14:57 -0700 |
| commit | 2dec77bf656d2fa360f782777ba5afa815839dec (patch) | |
| tree | eb544917a56dd8b0e0d4cf3b4013f025679a455f | |
| parent | 02b2b76fb0d3eeab8bfe7fb43f8413c8ccb4690d (diff) | |
drivers/misc: make the HDCP lib a standalone driver
Currently the hdcp lib doesn't have a context and
just acts as a lib for HDCP compliant interfaces like
HDMI and Display Port.
Make this lib a standalone driver capable of supporting
sysfs nodes to make communication with other modules
like TZ easier and less roundabout.
Change-Id: If693a9d4c8561e6d8c94e236a0fc108c8a65c05e
Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org>
| -rw-r--r-- | Documentation/devicetree/bindings/msm_hdcp/msm_hdcp.txt | 14 | ||||
| -rw-r--r-- | drivers/misc/hdcp.c | 256 | ||||
| -rw-r--r-- | include/linux/hdcp_qseecom.h | 5 |
3 files changed, 273 insertions, 2 deletions
diff --git a/Documentation/devicetree/bindings/msm_hdcp/msm_hdcp.txt b/Documentation/devicetree/bindings/msm_hdcp/msm_hdcp.txt new file mode 100644 index 000000000000..8d5f55d7a8ca --- /dev/null +++ b/Documentation/devicetree/bindings/msm_hdcp/msm_hdcp.txt @@ -0,0 +1,14 @@ +MSM HDCP driver + +Standalone driver managing HDCP related communications +between TZ and HLOS for MSM chipset. + +Required properties: + +compatible = "qcom,msm-hdcp"; + +Example: + +qcom_msmhdcp: qcom,msm_hdcp { + compatible = "qcom,msm-hdcp"; +}; diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c index 6dabb92bc8ce..77ce6b34503c 100644 --- a/drivers/misc/hdcp.c +++ b/drivers/misc/hdcp.c @@ -12,10 +12,13 @@ #define pr_fmt(fmt) "%s: " fmt, __func__ +#include <linux/platform_device.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/fs.h> +#include <linux/file.h> +#include <linux/uaccess.h> #include <linux/cdev.h> #include <linux/sched.h> #include <linux/list.h> @@ -30,9 +33,26 @@ #include <linux/errno.h> #include <linux/hdcp_qseecom.h> #include <linux/kthread.h> +#include <linux/of.h> +#include <video/msm_hdmi_hdcp_mgr.h> #include "qseecom_kernel.h" +struct msm_hdcp_mgr { + struct platform_device *pdev; + dev_t dev_num; + struct cdev cdev; + struct class *class; + struct device *device; + struct HDCP_V2V1_MSG_TOPOLOGY cached_tp; + u32 tp_msgid; +}; + +#define CLASS_NAME "hdcp" +#define DRIVER_NAME "msm_hdcp" + +static struct msm_hdcp_mgr *hdcp_drv_mgr; + #define TZAPP_NAME "hdcp2p2" #define HDCP1_APP_NAME "hdcp1" #define QSEECOM_SBUFF_SIZE 0x1000 @@ -2433,3 +2453,239 @@ void hdcp_library_deregister(void *phdcpcontext) kzfree(handle); } EXPORT_SYMBOL(hdcp_library_deregister); + +void hdcp1_notify_topology(void) +{ + char *envp[4]; + char *a; + char *b; + + a = kzalloc(SZ_16, GFP_KERNEL); + + if (!a) + return; + + b = kzalloc(SZ_16, GFP_KERNEL); + + if (!b) { + kfree(a); + return; + } + + envp[0] = "HDCP_MGR_EVENT=MSG_READY"; + envp[1] = a; + envp[2] = b; + envp[3] = NULL; + + snprintf(envp[1], 16, "%d", (int)DOWN_CHECK_TOPOLOGY); + snprintf(envp[2], 16, "%d", (int)HDCP_V1_TX); + kobject_uevent_env(&hdcp_drv_mgr->device->kobj, KOBJ_CHANGE, envp); + kfree(a); + kfree(b); +} + +static ssize_t msm_hdcp_1x_sysfs_rda_tp(struct device *dev, +struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + + if (!hdcp_drv_mgr) { + pr_err("invalid input\n"); + return -EINVAL; + } + + switch (hdcp_drv_mgr->tp_msgid) { + case DOWN_CHECK_TOPOLOGY: + case DOWN_REQUEST_TOPOLOGY: + buf[MSG_ID_IDX] = hdcp_drv_mgr->tp_msgid; + buf[RET_CODE_IDX] = HDCP_AUTHED; + ret = HEADER_LEN; + + memcpy(buf + HEADER_LEN, &hdcp_drv_mgr->cached_tp, + sizeof(struct HDCP_V2V1_MSG_TOPOLOGY)); + + ret += sizeof(struct HDCP_V2V1_MSG_TOPOLOGY); + + /* clear the flag once data is read back to user space*/ + hdcp_drv_mgr->tp_msgid = -1; + break; + default: + ret = -EINVAL; + } + + return ret; +} /* hdcp_1x_sysfs_rda_tp*/ + +static ssize_t msm_hdcp_1x_sysfs_wta_tp(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int msgid = 0; + ssize_t ret = count; + + if (!hdcp_drv_mgr || !buf) { + pr_err("invalid input\n"); + return -EINVAL; + } + + msgid = buf[0]; + + switch (msgid) { + case DOWN_CHECK_TOPOLOGY: + case DOWN_REQUEST_TOPOLOGY: + hdcp_drv_mgr->tp_msgid = msgid; + break; + /* more cases added here */ + default: + ret = -EINVAL; + } + + return ret; +} /* hdmi_tx_sysfs_wta_hpd */ + +static DEVICE_ATTR(tp, S_IRUGO | S_IWUSR, msm_hdcp_1x_sysfs_rda_tp, + msm_hdcp_1x_sysfs_wta_tp); + +void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp) +{ + memcpy((void *)&hdcp_drv_mgr->cached_tp, + hdcp1_cached_tp, + sizeof(struct HDCP_V2V1_MSG_TOPOLOGY)); +} + +static struct attribute *msm_hdcp_fs_attrs[] = { + &dev_attr_tp.attr, + NULL +}; + +static struct attribute_group msm_hdcp_fs_attr_group = { + .attrs = msm_hdcp_fs_attrs +}; + +static int msm_hdcp_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int msm_hdcp_close(struct inode *inode, struct file *file) +{ + return 0; +} + +static const struct file_operations msm_hdcp_fops = { + .owner = THIS_MODULE, + .open = msm_hdcp_open, + .release = msm_hdcp_close, +}; + +static const struct of_device_id msm_hdcp_dt_match[] = { + { .compatible = "qcom,msm-hdcp",}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_hdcp_dt_match); + +static int msm_hdcp_probe(struct platform_device *pdev) +{ + int ret; + + hdcp_drv_mgr = devm_kzalloc(&pdev->dev, sizeof(struct msm_hdcp_mgr), + GFP_KERNEL); + if (!hdcp_drv_mgr) + return -ENOMEM; + + hdcp_drv_mgr->pdev = pdev; + + platform_set_drvdata(pdev, hdcp_drv_mgr); + + ret = alloc_chrdev_region(&hdcp_drv_mgr->dev_num, 0, 1, DRIVER_NAME); + if (ret < 0) { + pr_err("alloc_chrdev_region failed ret = %d\n", ret); + goto error_get_dev_num; + } + + hdcp_drv_mgr->class = class_create(THIS_MODULE, CLASS_NAME); + if (IS_ERR(hdcp_drv_mgr->class)) { + ret = PTR_ERR(hdcp_drv_mgr->class); + pr_err("couldn't create class rc = %d\n", ret); + goto error_class_create; + } + + hdcp_drv_mgr->device = device_create(hdcp_drv_mgr->class, NULL, + hdcp_drv_mgr->dev_num, NULL, DRIVER_NAME); + if (IS_ERR(hdcp_drv_mgr->device)) { + ret = PTR_ERR(hdcp_drv_mgr->device); + pr_err("device_create failed %d\n", ret); + goto error_class_device_create; + } + + cdev_init(&hdcp_drv_mgr->cdev, &msm_hdcp_fops); + ret = cdev_add(&hdcp_drv_mgr->cdev, + MKDEV(MAJOR(hdcp_drv_mgr->dev_num), 0), 1); + if (ret < 0) { + pr_err("cdev_add failed %d\n", ret); + goto error_cdev_add; + } + + ret = sysfs_create_group(&hdcp_drv_mgr->device->kobj, + &msm_hdcp_fs_attr_group); + if (ret) + pr_err("unable to register rotator sysfs nodes\n"); + + return 0; +error_cdev_add: + device_destroy(hdcp_drv_mgr->class, hdcp_drv_mgr->dev_num); +error_class_device_create: + class_destroy(hdcp_drv_mgr->class); +error_class_create: + unregister_chrdev_region(hdcp_drv_mgr->dev_num, 1); +error_get_dev_num: + devm_kfree(&pdev->dev, hdcp_drv_mgr); + hdcp_drv_mgr = NULL; + return ret; +} + +static int msm_hdcp_remove(struct platform_device *pdev) +{ + struct msm_hdcp_mgr *mgr; + + mgr = (struct msm_hdcp_mgr *)platform_get_drvdata(pdev); + if (!mgr) + return -ENODEV; + + sysfs_remove_group(&hdcp_drv_mgr->device->kobj, + &msm_hdcp_fs_attr_group); + cdev_del(&hdcp_drv_mgr->cdev); + device_destroy(hdcp_drv_mgr->class, hdcp_drv_mgr->dev_num); + class_destroy(hdcp_drv_mgr->class); + unregister_chrdev_region(hdcp_drv_mgr->dev_num, 1); + + devm_kfree(&pdev->dev, hdcp_drv_mgr); + hdcp_drv_mgr = NULL; + return 0; +} + +static struct platform_driver msm_hdcp_driver = { + .probe = msm_hdcp_probe, + .remove = msm_hdcp_remove, + .driver = { + .name = "msm_hdcp", + .of_match_table = msm_hdcp_dt_match, + .pm = NULL, + } +}; + +static int __init msm_hdcp_init(void) +{ + return platform_driver_register(&msm_hdcp_driver); +} + +static void __exit msm_hdcp_exit(void) +{ + return platform_driver_unregister(&msm_hdcp_driver); +} + +module_init(msm_hdcp_init); +module_exit(msm_hdcp_exit); + +MODULE_DESCRIPTION("MSM HDCP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/hdcp_qseecom.h b/include/linux/hdcp_qseecom.h index 68f2dd993170..dc4af867a3bc 100644 --- a/include/linux/hdcp_qseecom.h +++ b/include/linux/hdcp_qseecom.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -146,5 +146,6 @@ void hdcp_library_deregister(void *phdcpcontext); bool hdcp1_check_if_supported_load_app(void); int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb); int hdcp1_set_enc(bool enable); - +void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp); +void hdcp1_notify_topology(void); #endif /* __HDCP_QSEECOM_H */ |
