/******************************************************************************
版权所有：	
文件名称：	sm2_dev.c
文件版本：	01.01
创建作者:		xxxxxx
创建日期：	2014.7.23
功能说明：	加密接口.

其它说明：
修改记录：
*/
#if !defined CPU_FUXI && !defined CPU_AM335X

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include <linux/phy.h>
#include <linux/wait.h> 
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/proc_fs.h>
#include <linux/circ_buf.h>
#include <asm/irq.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/pgtable.h>
#include <asm/cacheflush.h>

#ifdef CPU_COLDFIRE
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
#endif

//***************************************
//以下定义是为了编译通过
#ifndef BYTE
#define BYTE unsigned char
#endif

#ifndef WORD
#define WORD unsigned short
#endif

#ifndef DWORD
#define DWORD unsigned int
#endif

#ifndef UINT
#define UINT unsigned short
#endif

#ifndef SINT
#define SINT short
#endif

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

typedef struct IEC101{
	int a;	
} IEC101_DEF;

typedef struct IEC104{
	int a;	
} IEC104_DEF;

//***************************************

#include "SM2.h"
#include "sm2_dev.h"
 

extern int readUserId(BYTE *dat);
extern int writeUserId(BYTE *dat);
extern int writeSM2key(BYTE no,BYTE *dat);
extern int readSM2key(BYTE no,BYTE *dat); 


//主设备号
static int major=GH_SM2_DEV_MAJOR;

//设备个数
#define GH_SM2_DEV_COUNT			1
//设备名
#define GH_SM2_DEV_NAME			"sm2_dev"


//gh_sm2_dev 设备数据结构
struct gh_sm2_dev{	
	int idx;								//设备编号
	struct cdev cdev; 						//字符设备数据结构
	atomic_t open_flag;						//打开标志
};


//gh_sm2_dev设备
static struct gh_sm2_dev g_gh_sm2_dev[GH_SM2_DEV_COUNT];

/******************************************************************************
函数名称：	gh_sm2_dev_open
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-07-14 
函数说明：	字符设备打开函数.
参数说明：	
			inode:文件节点.
			file: 打开的文件						
返回值：	成功返回0，失败返回负数
修改记录：	
*/
static int gh_sm2_dev_open(struct inode *inode, struct file *file)
{
	struct gh_sm2_dev *dev;
	//得到gh_sm2_dev
	dev=container_of(inode->i_cdev, struct gh_sm2_dev, cdev);
	//保存gh_sm2_dev，便于以后使用
	file->private_data=dev;
    
    //设备是否已经打开
	if(atomic_inc_return(&dev->open_flag)>1){
	
		atomic_dec(&dev->open_flag);
		return -EBUSY; 
	
	}  

	
	return 0;	
}

/******************************************************************************
函数名称：	gh_sm2_dev_write
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-07-14 
函数说明：	字符设备写函数.
参数说明：	
			file: 打开的文件.
			data: 用户空间数据.
			len:	发送长度.
			ppos:	文件偏移位置												
返回值：		成功返回发送的字节数，失败返回负数
修改记录：	
*/
static ssize_t gh_sm2_dev_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
{
	return 0;
}

/******************************************************************************
函数名称：	gh_sm2_dev_read
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-07-14  
函数说明：	字符设备读函数.
参数说明：	
			file: 打开的文件.
			buf: 用户空间缓冲区.
			len:	读长度.
			ppos:	文件偏移位置												
返回值：		成功返回读取的字节数，失败返回负数
修改记录：	
*/
static ssize_t gh_sm2_dev_read(struct file *file, char __user *data, size_t len, loff_t *ppos)
{
    
	return  0;
}


/******************************************************************************
函数名称：	gh_sm2_dev_ioctl
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-07-14  
函数说明：	字符设备ioctl函数.
参数说明：	
			inode:文件节点.
			file: 打开的文件.	
			cmd:	命令.				
			arg:	参数.									
返回值：		成功返回0，失败返回负数
修改记录：	
*/
#ifdef CPU_AM335X
static long gh_sm2_dev_ioctl(struct file *file, unsigned int cmd, uint32_t arg)
#else
static int gh_sm2_dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, uint32_t arg)
#endif
{
	Twr_UserId *p_wrui;
	Twr_SM2key *p_sm2key;	
	Twr_SM2key  sm2key;
	TSM2_GenerateRandom_me *p_gr;
	TSM2_GenerateRandom_me gr;
	Tencrypt_epri *p_enep;
	Tencrypt_epri enep;
	TSM2_Encrypt *p_sm2enrypt;
	TSM2_Encrypt sm2enrypt;
	TSM2_Verify *p_sm2verify;
	TSM2_Verify sm2verify;
	unsigned int out_len=0;
	unsigned char dat[68];
	int ret = 0;
	
	switch(cmd)
	{
		case GH_SM2_DEV_READUSERID:  //readUserId
			ret = readUserId(dat);		 
			if(ret == 0)
			{
				p_wrui = (Twr_UserId *)arg;
				if(copy_to_user(p_wrui->dat, dat, 16))
					return -EFAULT;		
			} else {
				return -EFAULT;		
			}		
			break;
			
		case GH_SM2_DEV_WRITEUSERID:	 //writeUserId
			p_wrui = (Twr_UserId *)arg;
			if(copy_from_user(dat, p_wrui->dat, 16))
				return -EFAULT;		
				
			ret = writeUserId(dat);	
			if(ret != 0)
			{
				return -EFAULT;	
			}
			break;
				
		case GH_SM2_DEV_READSM2KEY:  //readSM2key
			sm2key.dat = dat;		
			p_sm2key = (Twr_SM2key *)arg;
			if(copy_from_user(&sm2key.no, &p_sm2key->no, sizeof(sm2key.no)))
			{
				return -EFAULT;	
			}
			ret = readSM2key(sm2key.no, sm2key.dat);
			if(ret == 0)
			{	
				if(copy_to_user(p_sm2key->dat, sm2key.dat, 68))
					return -EFAULT;						
			}			 
			break;
			
		case GH_SM2_DEV_WRITESM2KEY:  //writeSM2key
			sm2key.dat = dat;
			p_sm2key = (Twr_SM2key *)arg;
			if(copy_from_user(&sm2key.no, &p_sm2key->no, sizeof(sm2key.no)))
				return -EFAULT;	
						
			if(copy_from_user(sm2key.dat, p_sm2key->dat, 68))
				return -EFAULT;	
			
			ret = writeSM2key(sm2key.no, sm2key.dat);
			if(ret != 0)
			{
				return -EFAULT;
			} 	
			break;	
			
				
		case GH_SM2_DEV_SM2_GENERATERANDOM_ME:  //SM2_GenerateRandom_me
			gr.pucRandom = dat;
			p_gr = (TSM2_GenerateRandom_me *)arg;
			if(copy_from_user(&gr.uiLength, &p_gr->uiLength, sizeof(gr.uiLength)))
				return -EFAULT;	
			ret = SM2_GenerateRandom_me(gr.uiLength, gr.pucRandom);	
			if(ret != 0)
				return -EFAULT;	
			if(copy_to_user(p_gr->pucRandom, gr.pucRandom, gr.uiLength))
				return -EFAULT;			
					
			break;
			
		case GH_SM2_DEV_ENCRYPTE_EPRI:   //encrypt_epri
			p_enep = (Tencrypt_epri *)arg;
			if(copy_from_user(&enep, p_enep, sizeof(enep)))
				return -EFAULT;		
			enep.in = kmalloc(enep.in_len, GFP_KERNEL);	
			if(!enep.in)
			{
				return -EFAULT;	
			}		
			enep.out = kmalloc(enep.in_len, GFP_KERNEL);	
			if(!enep.out)
			{
				kfree(enep.in);
				return -EFAULT;	
			}		
			
			if(copy_from_user(enep.in, p_enep->in, enep.in_len))
			{
				kfree(enep.in);
				kfree(enep.out);
				return -EFAULT;
			}
			
			enep.out_len = &out_len;
	 
			encrypt_epri(enep.in, enep.in_len, enep.out, &out_len, enep.key, enep.type);
						
			if(copy_to_user(p_enep->out, enep.out, out_len))
			{
				kfree(enep.in);
				kfree(enep.out);
				return -EFAULT;					
			}
			
			if(copy_to_user(p_enep->out_len, enep.out_len, sizeof(unsigned int)))
			{
				kfree(enep.in);
				kfree(enep.out);
				return -EFAULT;					
			}		
						
			kfree(enep.in);
			kfree(enep.out);
										
			break;	
		case GH_SM2_DEV_SM2_ENCRYPT:  //SM2_Encrypt
			p_sm2enrypt = (TSM2_Encrypt *)arg;
			if(copy_from_user(&sm2enrypt, p_sm2enrypt, sizeof(sm2enrypt)))
				return -EFAULT;
									
			sm2enrypt.pucDataInput = kmalloc(sm2enrypt.uiInputLength, GFP_KERNEL);	
			if(!sm2enrypt.pucDataInput)
			{
				return -EFAULT;	
			}		

			sm2enrypt.pucPublicKey = kmalloc(sizeof(ECCrefPublicKey), GFP_KERNEL);	
			if(!sm2enrypt.pucPublicKey)
			{
				kfree(sm2enrypt.pucDataInput);
				return -EFAULT;	
			}	

			sm2enrypt.pucRandom = kmalloc(sm2enrypt.uiRandomLength, GFP_KERNEL);	
			if(!sm2enrypt.pucRandom)
			{
				kfree(sm2enrypt.pucDataInput);
				kfree(sm2enrypt.pucPublicKey);
				return -EFAULT;	
			}			
			sm2enrypt.pucEncData = kmalloc(sizeof(ECCCipher), GFP_KERNEL);	
			if(!sm2enrypt.pucEncData)
			{
				kfree(sm2enrypt.pucDataInput);
				kfree(sm2enrypt.pucPublicKey);
				kfree(sm2enrypt.pucRandom);
				return -EFAULT;	
			}				
			ret = SM2_Encrypt(sm2enrypt.pucDataInput, sm2enrypt.uiInputLength, sm2enrypt.pucPublicKey, sm2enrypt.pucRandom, sm2enrypt.uiRandomLength, sm2enrypt.pucEncData);
			if(ret != 0 )
			{
				kfree(sm2enrypt.pucDataInput);
				kfree(sm2enrypt.pucPublicKey);
				kfree(sm2enrypt.pucRandom);
				kfree(sm2enrypt.pucEncData);
				return -EFAULT;			
			}
			
			if(copy_to_user(p_sm2enrypt->pucEncData, sm2enrypt.pucEncData, sizeof(ECCCipher)))
			{
				kfree(sm2enrypt.pucDataInput);
				kfree(sm2enrypt.pucPublicKey);
				kfree(sm2enrypt.pucRandom);
				kfree(sm2enrypt.pucEncData);
				return -EFAULT;						
			}
						
			kfree(sm2enrypt.pucDataInput);
			kfree(sm2enrypt.pucPublicKey);
			kfree(sm2enrypt.pucRandom);
			kfree(sm2enrypt.pucEncData);		
				
			break;
			
			
		case GH_SM2_DEV_SM2_VERIFY:	 //SM2_Verify
			p_sm2verify = (TSM2_Verify *)arg;
			if(copy_from_user(&sm2verify, p_sm2verify, sizeof(sm2verify)))
				return -EFAULT;	
			
				
			sm2verify.pucDataInput = kmalloc(sm2verify.uiInputLength, GFP_KERNEL);	
			if(!sm2verify.pucDataInput)
			{
				return -EFAULT;	
			}		
			
			sm2verify.pucID = kmalloc(sm2verify.uiIDLength, GFP_KERNEL);	
			if(!sm2verify.pucID)
			{
				kfree(sm2verify.pucDataInput);
				return -EFAULT;	
			}			
			
			sm2verify.pucPublicKey = kmalloc(sizeof(ECCrefPublicKey), GFP_KERNEL);	
			if(!sm2verify.pucPublicKey)
			{
				kfree(sm2verify.pucDataInput);
				kfree(sm2verify.pucID);
				return -EFAULT;	
			}	
			
			sm2verify.pucSignature = kmalloc(sizeof(ECCSignature), GFP_KERNEL);	
			if(!sm2verify.pucSignature)
			{
				kfree(sm2verify.pucDataInput);
				kfree(sm2verify.pucID);
				kfree(sm2verify.pucPublicKey);
				return -EFAULT;	
			}		

			if(copy_from_user(sm2verify.pucDataInput, p_sm2verify->pucDataInput, sm2verify.uiInputLength))
			{
				kfree(sm2verify.pucDataInput);
				kfree(sm2verify.pucID);
				kfree(sm2verify.pucPublicKey);		
				kfree(sm2verify.pucSignature);	
				return -EFAULT;
			}
			

			if(copy_from_user(sm2verify.pucID, p_sm2verify->pucID, sm2verify.uiIDLength))
			{
				kfree(sm2verify.pucDataInput);
				kfree(sm2verify.pucID);
				kfree(sm2verify.pucPublicKey);		
				kfree(sm2verify.pucSignature);	
				return -EFAULT;
			}		

			if(copy_from_user(sm2verify.pucPublicKey, p_sm2verify->pucPublicKey, sizeof(ECCrefPublicKey)))
			{
				kfree(sm2verify.pucDataInput);
				kfree(sm2verify.pucID);
				kfree(sm2verify.pucPublicKey);		
				kfree(sm2verify.pucSignature);	
				return -EFAULT;
			}		 	
			
			if(copy_from_user(sm2verify.pucSignature, p_sm2verify->pucSignature, sizeof(ECCSignature)))
			{
				kfree(sm2verify.pucDataInput);
				kfree(sm2verify.pucID);
				kfree(sm2verify.pucPublicKey);		
				kfree(sm2verify.pucSignature);	
				return -EFAULT;
			}		 	
							
			ret = SM2_Verify(sm2verify.pucDataInput, sm2verify.uiInputLength, sm2verify.pucID, sm2verify.uiIDLength, sm2verify.pucPublicKey, sm2verify.pucSignature);
	
			if(ret != 0)
			{
				kfree(sm2verify.pucDataInput);
				kfree(sm2verify.pucID);
				kfree(sm2verify.pucPublicKey);		
				kfree(sm2verify.pucSignature);	
				return -EFAULT;			
			}
			
			kfree(sm2verify.pucDataInput);
			kfree(sm2verify.pucID);
			kfree(sm2verify.pucPublicKey);		
			kfree(sm2verify.pucSignature);				
											
			break;		
		default:
			ret = -EFAULT;	
			break;									
	}	

	 
	return ret;	
}
/******************************************************************************
函数名称：	gh_sm2_dev_release
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-07-14  
函数说明：	字符设备关闭函数.
参数说明：	
			inode:文件节点.
			file: 打开的文件													
返回值：		总是返回0
修改记录：	
*/
static int gh_sm2_dev_release(struct inode *inode, struct file *file)
{
	struct gh_sm2_dev *dev; 
  
  dev=container_of(inode->i_cdev, struct gh_sm2_dev, cdev);
	atomic_dec(&dev->open_flag);
	
	return 0;
}




static const struct file_operations gh_sm2_dev_fops = {
	.owner	= THIS_MODULE,
	.write	= gh_sm2_dev_write,
	.read	= gh_sm2_dev_read,
	.open	= gh_sm2_dev_open,
#ifdef CPU_AM335X	
	.unlocked_ioctl = gh_sm2_dev_ioctl,
#else
	.ioctl	= gh_sm2_dev_ioctl,
#endif	
	.release = gh_sm2_dev_release,		
	
};


/******************************************************************************
函数名称：	gh_sm2_dev_init_drvinfo
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-07-14  
函数说明：	初始化设备数据结构.
参数说明：	无							
返回值：	无
修改记录：	
*/
static void gh_sm2_dev_init_drvinfo(void)
{
	int i=0;

	memset(g_gh_sm2_dev, 0, sizeof(struct gh_sm2_dev)*GH_SM2_DEV_COUNT);
	
	for(i=0;i<GH_SM2_DEV_COUNT;i++)
	{
		//初始化字符设备
		cdev_init(&g_gh_sm2_dev[i].cdev, &gh_sm2_dev_fops);
		cdev_add(&g_gh_sm2_dev[i].cdev, MKDEV(major, i), 1);	
		
		//设备编号(序号)
		g_gh_sm2_dev[i].idx=i;
	}	
	
		
}

/******************************************************************************
函数名称：	gh_sm2_dev_init
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-07-14  
函数说明：	模块初始化函数.
参数说明：	无							
返回值：	0表示成功，-1表示失败
修改记录：	
*/
int gh_sm2_dev_init(void)
{
	dev_t	dev_id;
	int	retval;


	//注册字符设备
	if (major) {
		dev_id = MKDEV(major, 0);
		retval = register_chrdev_region(dev_id, GH_SM2_DEV_COUNT, GH_SM2_DEV_NAME);
	} else {
		retval = alloc_chrdev_region(&dev_id, 0, GH_SM2_DEV_COUNT, GH_SM2_DEV_NAME);
		major = MAJOR(dev_id);
	}	

	if (retval) {
		return -1;
	}	

 	//初始化设备数据结构
	gh_sm2_dev_init_drvinfo();
	
	
	return 0;	
}

/******************************************************************************
函数名称：	gh_sm2_dev_exit
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-07-14  
函数说明：	模块卸载函数.
参数说明：	无							
返回值：	无
修改记录：	
*/
void gh_sm2_dev_exit(void)
{
	dev_t dev_id = MKDEV(major, 0);
	int i=0;

	
	for(i=0;i<GH_SM2_DEV_COUNT;i++)
	{
		//移除字符设备
		cdev_del(&g_gh_sm2_dev[i].cdev);
	}
	unregister_chrdev_region(dev_id, GH_SM2_DEV_COUNT);	
}

//module_init(gh_sm2_dev_init);
//module_exit(gh_sm2_dev_exit);

//MODULE_AUTHOR("JHW");
//MODULE_DESCRIPTION("gh_sm2_dev driver");
//MODULE_LICENSE("GPL");

#endif

