229 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| #include <linux/module.h>
 | |
| #include <linux/proc_fs.h>
 | |
| #include <linux/seq_file.h>
 | |
| #include <linux/fs.h>
 | |
| #include <linux/init.h>
 | |
| #include <linux/proc_fs.h>
 | |
| #include <linux/uaccess.h>
 | |
| #include "dispdev_proc.h"
 | |
| #include "dispdev_dbg.h"
 | |
| #include "dispdev_main.h"
 | |
| #include "dispdev_api.h"
 | |
| 
 | |
| 
 | |
| //============================================================================
 | |
| // Define
 | |
| //============================================================================
 | |
| #define MAX_CMD_LENGTH 30
 | |
| #define MAX_ARG_NUM     6
 | |
| 
 | |
| //============================================================================
 | |
| // Declaration
 | |
| //============================================================================
 | |
| typedef struct proc_cmd {
 | |
| 	char cmd[MAX_CMD_LENGTH];
 | |
| 	int (*execute)(PMODULE_INFO pdrv, unsigned char argc, char **argv);
 | |
| } PROC_CMD, *PPROC_CMD;
 | |
| 
 | |
| //============================================================================
 | |
| // Global variable
 | |
| //============================================================================
 | |
| PDISPDEV_DRV_INFO pdrv_info_data;
 | |
| 
 | |
| //============================================================================
 | |
| // Function define
 | |
| //============================================================================
 | |
| 
 | |
| 
 | |
| //=============================================================================
 | |
| // proc "Custom Command" file operation functions
 | |
| //=============================================================================
 | |
| static PROC_CMD cmd_read_list[] = {
 | |
| 	// keyword          function name
 | |
| 	{ "reg",            nvt_dispdev_api_read_reg           },
 | |
| };
 | |
| 
 | |
| #define NUM_OF_READ_CMD (sizeof(cmd_read_list) / sizeof(PROC_CMD))
 | |
| 
 | |
| static PROC_CMD cmd_write_list[] = {
 | |
| 	// keyword          function name
 | |
| 	{ "reg",            nvt_dispdev_api_write_reg          },
 | |
| 	{ "pattern",        nvt_dispdev_api_write_pattern       }
 | |
| };
 | |
| 
 | |
| #define NUM_OF_WRITE_CMD (sizeof(cmd_write_list) / sizeof(PROC_CMD))
 | |
| 
 | |
| static int nvt_dispdev_proc_cmd_show(struct seq_file *sfile, void *v)
 | |
| {
 | |
| 	nvt_dbg(IND, "\n");
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int nvt_dispdev_proc_cmd_open(struct inode *inode, struct file *file)
 | |
| {
 | |
| 	nvt_dbg(IND, "\n");
 | |
| 	return single_open(file, nvt_dispdev_proc_cmd_show, &pdrv_info_data->module_info);
 | |
| }
 | |
| 
 | |
| static ssize_t nvt_dispdev_proc_cmd_write(struct file *file, const char __user *buf,
 | |
| 		size_t size, loff_t *off)
 | |
| {
 | |
| 	int len = size;
 | |
| 	int ret = -EINVAL;
 | |
| 	char cmd_line[MAX_CMD_LENGTH];
 | |
| 	char *cmdstr = cmd_line;
 | |
| 	const char delimiters[] = {' ', 0x0A, 0x0D, '\0'};
 | |
| 	char *argv[MAX_ARG_NUM] = {0};
 | |
| 	unsigned char ucargc = 0;
 | |
| 	unsigned char loop;
 | |
| 
 | |
| 	// check command length
 | |
| 	if (len > (MAX_CMD_LENGTH - 1)) {
 | |
| 		nvt_dbg(ERR, "Command length is too long!\n");
 | |
| 		goto ERR_OUT;
 | |
| 	}
 | |
| 
 | |
| 	// copy command string from user space
 | |
| 	if (copy_from_user(cmd_line, buf, len)) {
 | |
| 		goto ERR_OUT;
 | |
| 	}
 | |
| 
 | |
| 	if (len == 0)
 | |
| 		cmd_line[0] = '\0';
 | |
| 	else
 | |
| 		cmd_line[len - 1] = '\0';
 | |
| 
 | |
| 	nvt_dbg(IND, "CMD:%s\n", cmd_line);
 | |
| 
 | |
| 	// parse command string
 | |
| 	for (ucargc = 0; ucargc < MAX_ARG_NUM; ucargc++) {
 | |
| 		argv[ucargc] = strsep(&cmdstr, delimiters);
 | |
| 
 | |
| 		if (argv[ucargc] == NULL) {
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// dispatch command handler
 | |
| 	if (strncmp(argv[0], "r", 2) == 0) {
 | |
| 		for (loop = 0 ; loop < NUM_OF_READ_CMD; loop++) {
 | |
| 			if (strncmp(argv[1], cmd_read_list[loop].cmd, MAX_CMD_LENGTH) == 0) {
 | |
| 				ret = cmd_read_list[loop].execute(&pdrv_info_data->module_info, ucargc - 2, &argv[2]);
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 		if (loop >= NUM_OF_READ_CMD) {
 | |
| 			goto ERR_INVALID_CMD;
 | |
| 		}
 | |
| 
 | |
| 	} else if (strncmp(argv[0], "w", 2) == 0)  {
 | |
| 
 | |
| 		for (loop = 0 ; loop < NUM_OF_WRITE_CMD ; loop++) {
 | |
| 			if (strncmp(argv[1], cmd_write_list[loop].cmd, MAX_CMD_LENGTH) == 0) {
 | |
| 				ret = cmd_write_list[loop].execute(&pdrv_info_data->module_info, ucargc - 2, &argv[2]);
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (loop >= NUM_OF_WRITE_CMD) {
 | |
| 			goto ERR_INVALID_CMD;
 | |
| 		}
 | |
| 
 | |
| 	} else {
 | |
| 		goto ERR_INVALID_CMD;
 | |
| 	}
 | |
| 
 | |
| 	return size;
 | |
| 
 | |
| ERR_INVALID_CMD:
 | |
| 	nvt_dbg(ERR, "Invalid CMD \"%s\"\n", cmd_line);
 | |
| 
 | |
| ERR_OUT:
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| static struct file_operations proc_cmd_fops = {
 | |
| 	.owner   = THIS_MODULE,
 | |
| 	.open    = nvt_dispdev_proc_cmd_open,
 | |
| 	.read    = seq_read,
 | |
| 	.llseek  = seq_lseek,
 | |
| 	.release = single_release,
 | |
| 	.write   = nvt_dispdev_proc_cmd_write
 | |
| };
 | |
| 
 | |
| //=============================================================================
 | |
| // proc "help" file operation functions
 | |
| //=============================================================================
 | |
| static int nvt_dispdev_proc_help_show(struct seq_file *sfile, void *v)
 | |
| {
 | |
| 	seq_printf(sfile, "=====================================================================\n");
 | |
| 	seq_printf(sfile, " Add message here\n");
 | |
| 	seq_printf(sfile, "=====================================================================\n");
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int nvt_dispdev_proc_help_open(struct inode *inode, struct file *file)
 | |
| {
 | |
| 	return single_open(file, nvt_dispdev_proc_help_show, NULL);
 | |
| }
 | |
| 
 | |
| static struct file_operations proc_help_fops = {
 | |
| 	.owner  = THIS_MODULE,
 | |
| 	.open   = nvt_dispdev_proc_help_open,
 | |
| 	.release = single_release,
 | |
| 	.read   = seq_read,
 | |
| 	.llseek = seq_lseek,
 | |
| };
 | |
| 
 | |
| int nvt_dispdev_proc_init(PDISPDEV_DRV_INFO pdrv_info)
 | |
| {
 | |
| 	int ret = 0;
 | |
| 	struct proc_dir_entry *pmodule_root = NULL;
 | |
| 	struct proc_dir_entry *pentry = NULL;
 | |
| 
 | |
| 	pmodule_root = proc_mkdir("dispdev", NULL);
 | |
| 	if (pmodule_root == NULL) {
 | |
| 		nvt_dbg(ERR, "failed to create Module root\n");
 | |
| 		ret = -EINVAL;
 | |
| 		goto remove_root;
 | |
| 	}
 | |
| 	pdrv_info->pproc_module_root = pmodule_root;
 | |
| 
 | |
| 
 | |
| 	pentry = proc_create("cmd", S_IRUGO | S_IXUGO, pmodule_root, &proc_cmd_fops);
 | |
| 	if (pentry == NULL) {
 | |
| 		nvt_dbg(ERR, "failed to create proc cmd!\n");
 | |
| 		ret = -EINVAL;
 | |
| 		goto remove_cmd;
 | |
| 	}
 | |
| 	pdrv_info->pproc_cmd_entry = pentry;
 | |
| 
 | |
| 	pentry = proc_create("help", S_IRUGO | S_IXUGO, pmodule_root, &proc_help_fops);
 | |
| 	if (pentry == NULL) {
 | |
| 		nvt_dbg(ERR, "failed to create proc help!\n");
 | |
| 		ret = -EINVAL;
 | |
| 		goto remove_cmd;
 | |
| 	}
 | |
| 	pdrv_info->pproc_help_entry = pentry;
 | |
| 
 | |
| 
 | |
| 	pdrv_info_data = pdrv_info;
 | |
| 
 | |
| 	return ret;
 | |
| 
 | |
| remove_cmd:
 | |
| 	proc_remove(pdrv_info->pproc_cmd_entry);
 | |
| 
 | |
| remove_root:
 | |
| 	proc_remove(pdrv_info->pproc_module_root);
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| int nvt_dispdev_proc_remove(PDISPDEV_DRV_INFO pdrv_info)
 | |
| {
 | |
| 	proc_remove(pdrv_info->pproc_help_entry);
 | |
| 	proc_remove(pdrv_info->pproc_cmd_entry);
 | |
| 	proc_remove(pdrv_info->pproc_module_root);
 | |
| 	return 0;
 | |
| }
 | 
