| /* |
| * Copyright (c) 2013-2016 TRUSTONIC LIMITED |
| * 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 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| #include <linux/ioctl.h> |
| #include <linux/device.h> |
| #include <linux/fs.h> |
| #include <linux/cdev.h> |
| #include <linux/completion.h> |
| #include <linux/slab.h> |
| #include <linux/uaccess.h> |
| #include <linux/switch.h> |
| |
| #include "tui_ioctl.h" |
| #include "tlcTui.h" |
| #include "mobicore_driver_api.h" |
| #include "dciTui.h" |
| #include "tui-hal.h" |
| #include "build_tag.h" |
| |
| /*static int tui_dev_major_number = 122; */ |
| |
| /*module_param(tui_dev_major_number, int, 0000); */ |
| /*MODULE_PARM_DESC(major, */ |
| /* "The device major number used to register a unique char device driver"); */ |
| |
| /* Static variables */ |
| static struct cdev tui_cdev; |
| |
| struct switch_dev tui_switch; |
| |
| int tui_force_close(uint32_t arg) |
| { |
| int ret = 0; |
| |
| pr_info("Force TUI_IO_NOTIFY %d\n", arg); |
| |
| if (tlc_notify_event(arg)) |
| ret = 0; |
| else |
| ret = -EFAULT; |
| return ret; |
| } |
| EXPORT_SYMBOL(tui_force_close); |
| |
| void tui_cover_mode_set (bool arg) |
| { |
| pr_info("tui cover mode set to %d\n", arg); |
| tui_cover_mode_on = arg; |
| } |
| EXPORT_SYMBOL(tui_cover_mode_set); |
| |
| static long tui_ioctl(struct file *f, unsigned int cmd, unsigned long arg) |
| { |
| int ret = -ENOTTY; |
| int __user *uarg = (int __user *)arg; |
| |
| if (_IOC_TYPE(cmd) != TUI_IO_MAGIC) |
| return -EINVAL; |
| |
| pr_info("t-base-tui module: ioctl 0x%x ", cmd); |
| |
| switch (cmd) { |
| case TUI_IO_SET_RESOLUTION: |
| pr_info("TLC_TUI_CMD_SET_RESOLUTION\n"); |
| /* NOT IMPLEMENTED */ |
| ret = 0; |
| break; |
| case TUI_IO_NOTIFY: |
| pr_info("TUI_IO_NOTIFY\n"); |
| |
| if (tlc_notify_event(arg)) |
| ret = 0; |
| else |
| ret = -EFAULT; |
| break; |
| |
| case TUI_IO_WAITCMD: { |
| struct tlc_tui_command_t tui_cmd = {0}; |
| |
| pr_info("TUI_IO_WAITCMD\n"); |
| |
| ret = tlc_wait_cmd(&tui_cmd); |
| if (ret) { |
| pr_debug("ERROR %s:%d tlc_wait_cmd returned (0x%08X)\n", |
| __func__, __LINE__, ret); |
| return ret; |
| } |
| |
| /* Write command id to user */ |
| pr_debug("IOCTL: sending command %d to user.\n", tui_cmd.id); |
| |
| if (copy_to_user(uarg, &tui_cmd, sizeof( |
| struct tlc_tui_command_t))) |
| ret = -EFAULT; |
| else |
| ret = 0; |
| |
| break; |
| } |
| |
| case TUI_IO_ACK: { |
| struct tlc_tui_response_t rsp_id; |
| |
| pr_info("TUI_IO_ACK\n"); |
| |
| /* Read user response */ |
| if (copy_from_user(&rsp_id, uarg, sizeof(rsp_id))) |
| ret = -EFAULT; |
| else |
| ret = 0; |
| |
| pr_debug("IOCTL: User completed command %d.\n", rsp_id.id); |
| ret = tlc_ack_cmd(&rsp_id); |
| if (ret) |
| return ret; |
| break; |
| } |
| |
| case TUI_IO_INIT_DRIVER: { |
| pr_info("TUI_IO_INIT_DRIVER\n"); |
| |
| ret = tlc_init_driver(); |
| if (ret) { |
| pr_debug("ERROR %s:%d tlc_init_driver returned (0x%08X)\n", |
| __func__, __LINE__, ret); |
| return ret; |
| } |
| break; |
| } |
| |
| default: |
| pr_info("ERROR %s:%d Unknown ioctl (%u)!\n", __func__, |
| __LINE__, cmd); |
| return -ENOTTY; |
| } |
| |
| return ret; |
| } |
| |
| atomic_t fileopened; |
| |
| static int tui_open(struct inode *inode, struct file *file) |
| { |
| pr_info("TUI file opened\n"); |
| atomic_inc(&fileopened); |
| return 0; |
| } |
| |
| static int tui_release(struct inode *inode, struct file *file) |
| { |
| pr_info("TUI file closed\n"); |
| if (atomic_dec_and_test(&fileopened)) |
| tlc_notify_event(NOT_TUI_CANCEL_EVENT); |
| |
| return 0; |
| } |
| |
| static const struct file_operations tui_fops = { |
| .owner = THIS_MODULE, |
| .unlocked_ioctl = tui_ioctl, |
| #ifdef CONFIG_COMPAT |
| .compat_ioctl = tui_ioctl, |
| #endif |
| .open = tui_open, |
| .release = tui_release |
| }; |
| |
| /*--------------------------------------------------------------------------- */ |
| static int __init tlc_tui_init(void) |
| { |
| pr_info("Loading t-base-tui module.\n"); |
| pr_debug("\n=============== Running TUI Kernel TLC ===============\n"); |
| pr_info("%s\n", MOBICORE_COMPONENT_BUILD_TAG); |
| |
| dev_t devno; |
| int err; |
| static struct class *tui_class; |
| |
| atomic_set(&fileopened, 0); |
| |
| err = alloc_chrdev_region(&devno, 0, 1, TUI_DEV_NAME); |
| if (err) { |
| pr_debug("Unable to allocate Trusted UI device number\n"); |
| return err; |
| } |
| |
| cdev_init(&tui_cdev, &tui_fops); |
| tui_cdev.owner = THIS_MODULE; |
| /* tui_cdev.ops = &tui_fops; */ |
| |
| err = cdev_add(&tui_cdev, devno, 1); |
| if (err) { |
| pr_debug("Unable to add Trusted UI char device\n"); |
| unregister_chrdev_region(devno, 1); |
| return err; |
| } |
| |
| tui_class = class_create(THIS_MODULE, "tui_cls"); |
| if (IS_ERR(tui_class)) { |
| pr_debug(KERN_ERR "Failed to create tui class.\n"); |
| unregister_chrdev_region(devno, 1); |
| cdev_del(&tui_cdev); |
| return -1; |
| } |
| |
| device_create(tui_class, NULL, devno, NULL, TUI_DEV_NAME); |
| |
| if (!hal_tui_init()) |
| return -EPERM; |
| |
| /* register the switch device for tui */ |
| tui_switch.name = "tui"; |
| err = switch_dev_register(&tui_switch); |
| if (err) |
| pr_debug(KERN_ERR "Failed to register tui_switch.\n"); |
| |
| return 0; |
| } |
| |
| static void __exit tlc_tui_exit(void) |
| { |
| pr_info("Unloading t-base-tui module.\n"); |
| |
| switch_dev_unregister(&tui_switch); |
| unregister_chrdev_region(tui_cdev.dev, 1); |
| cdev_del(&tui_cdev); |
| |
| hal_tui_exit(); |
| } |
| |
| module_init(tlc_tui_init); |
| module_exit(tlc_tui_exit); |
| |
| MODULE_AUTHOR("Trustonic Limited"); |
| MODULE_LICENSE("GPL v2"); |
| MODULE_DESCRIPTION("Kinibi TUI"); |