1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2025-08-04 15:30:24 +00:00
Files
physwizz 99537be4e2 first
2024-03-11 06:53:12 +11:00

237 lines
5.0 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 MediaTek Inc.
*/
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/dma-buf.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kdev_t.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include "widevine_driver.h"
#include "mtk_heap.h"
static dev_t wv_devt;
static struct cdev *wv_cdev;
static struct class *wv_class;
static struct device *wv_device;
int wv_dbg_level;
module_param(wv_dbg_level, int, 0644);
/******open file function********/
int wv_open(struct inode *inode, struct file *filep)
{
WV_LOG(1, "filep->f_op = %p\n", filep->f_op);
return 0;
}
/**close file***/
int wv_release(struct inode *inode, struct file *filep)
{
WV_LOG(1, "filep->f_op = %p\n", filep->f_op);
return 0;
}
/*******IO control*********/
static long wv_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
int ret = 0;
uint32_t sec_handle = 0;
struct WV_FD_TO_SEC_HANDLE in_out_param;
struct dma_buf *dmabuf = NULL;
WV_LOG(1, "enter ioctl\n");
switch (cmd) {
case WV_IOC_GET_SEC_HANDLE:
WV_LOG(1, "WV_IOC_GET_SEC_HANDLE\n");
if (copy_from_user(&in_out_param, (void *)arg,
sizeof(struct WV_FD_TO_SEC_HANDLE))) {
WV_LOG(0, "Copy from user error\n");
ret = -EFAULT;
goto err_quit;
}
WV_LOG(1, "share_fd = %d\n", in_out_param.share_fd);
// get dma buf
dmabuf = dma_buf_get(in_out_param.share_fd);
if (IS_ERR_OR_NULL(dmabuf)) {
WV_LOG(0, "dma_buf_get fail: %ld\n", PTR_ERR(dmabuf));
ret = -EFAULT;
goto err_quit;
}
// get secure handle
sec_handle = dmabuf_to_secure_handle(dmabuf);
if (!sec_handle) {
WV_LOG(0, "get secure handle failed\n");
ret = -EFAULT;
goto err_quit;
}
in_out_param.sec_handle = sec_handle;
if (copy_to_user((void *)arg, &in_out_param, sizeof(struct WV_FD_TO_SEC_HANDLE))) {
WV_LOG(0, "Copy to user error\n");
ret = -EFAULT;
goto err_quit;
}
break;
default:
WV_LOG(0, "unknown ioctl cmd\n");
ret = -EINVAL;
break;
}
err_quit:
if (!IS_ERR_OR_NULL(dmabuf))
dma_buf_put(dmabuf);
return ret;
}
#if IS_ENABLED(CONFIG_COMPAT)
static long compat_wv_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
WV_LOG(1, "use compatible ioctl\n");
return wv_cdev->ops->unlocked_ioctl(filep, cmd, arg);
}
#endif
/*****file operation structure********/
static const struct file_operations wv_fops = {
.owner = THIS_MODULE,
.open = wv_open,
.release = wv_release,
.unlocked_ioctl = wv_ioctl,
#if IS_ENABLED(CONFIG_COMPAT)
.compat_ioctl = compat_wv_ioctl,
#endif
};
static int wv_probe(struct platform_device *pdev)
{
int ret = 0;
WV_LOG(0, "start probe\n");
// create char device
ret = alloc_chrdev_region(&wv_devt, 0, 1, WV_DEVNAME);
if (ret < 0) {
WV_LOG(0, "alloc_chrdev_region failed, %d\n", ret);
return ret;
}
// Allocate driver
wv_cdev = cdev_alloc();
if (wv_cdev == NULL) {
WV_LOG(0, "cdev_alloc failed\n");
ret = -ENOMEM;
goto out;
}
// Attach file operation
cdev_init(wv_cdev, &wv_fops);
wv_cdev->owner = THIS_MODULE;
wv_cdev->ops = &wv_fops;
// Add to system
ret = cdev_add(wv_cdev, wv_devt, 1);
if (ret < 0) {
WV_LOG(0, "cdev_add failed, %d\n", ret);
goto out;
}
wv_class = class_create(THIS_MODULE, WV_DEVNAME);
if (!wv_class) {
ret = -1;
WV_LOG(0, "class_create error\n");
goto out;
}
wv_device = device_create(wv_class, NULL, wv_devt, NULL, WV_DEVNAME);
if (!wv_device) {
ret = -1;
WV_LOG(0, "device_create error\n");
goto out;
}
WV_LOG(0, "probe done\n");
return 0;
out:
// Release char driver
if (wv_cdev != NULL) {
cdev_del(wv_cdev);
wv_cdev = NULL;
}
unregister_chrdev_region(wv_devt, 1);
return ret;
}
static int wv_remove(struct platform_device *pdev)
{
WV_LOG(0, "remove device\n");
device_destroy(wv_class, wv_devt);
class_destroy(wv_class);
// Release char driver
if (wv_cdev != NULL) {
cdev_del(wv_cdev);
wv_cdev = NULL;
}
unregister_chrdev_region(wv_devt, 1);
return 0;
}
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id wv_of_match[] = {
{.compatible = "mediatek,drm_wv",},
{}
};
#endif
MODULE_DEVICE_TABLE(of, wv_of_match);
static struct platform_driver mtk_wv_driver = {
.probe = wv_probe,
.remove = wv_remove,
.driver = {
.name = WV_DEVNAME,
.owner = THIS_MODULE,
#if IS_ENABLED(CONFIG_OF)
.of_match_table = wv_of_match,
#endif
},
};
static int __init mtk_wv_init(void)
{
WV_LOG(0, "Register the widevine driver\n");
if (platform_driver_register(&mtk_wv_driver)) {
WV_LOG(0, "failed to register widevine device\n");
return -ENODEV;
}
return 0;
}
/*uninstall device*/
static void __exit mtk_wv_exit(void)
{
platform_driver_unregister(&mtk_wv_driver);
WV_LOG(0, "driver exit successful\n");
}
module_init(mtk_wv_init);
module_exit(mtk_wv_exit);
MODULE_AUTHOR("Shan Zhang <shan.zhang@mediatek.com>");
MODULE_DESCRIPTION("Widevine Drm Driver");
MODULE_LICENSE("GPL");