#include
#include
#include
#include
#include
#include
#include
#include "reg.h"
static void *vbase;
static unsigned int vsize;
static void reg_unmap(void)
{
if(vbase){
iounmap(vbase);
}
vbase = NULL;
}
static long reg_set_map(struct file *file, unsigned long arg)
{
struct reg_base base;
if(copy_from_user(&base, (void*)arg, sizeof(base))){
return -EFAULT;
}
reg_unmap();
vbase = ioremap(base.base, base.size);
if(NULL == vbase){
return -EINVAL;
}
vsize = base.size;
return 0;
}
static long reg_read_value(struct file *file, unsigned long arg)
{
struct reg_value value;
if(copy_from_user(&value, (void*)arg, sizeof(value))){
return -EFAULT;
}
if(NULL == vbase || value.addr > vsize - 4){
return -EINVAL;
}
value.value = readl(vbase + value.addr);
if(copy_to_user((void*)arg, &value, sizeof(value))){
return -EFAULT;
}
return 0;
}
static long reg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret = -ENOIOCTLCMD;
switch(cmd)
{
case REG_CMD_BASE:
ret = reg_set_map(file, arg);
break;
case REG_CMD_VALUE:
ret = reg_read_value(file, arg);
break;
default:
break;
}
return ret;
}
static struct file_operations fops =
{
.unlocked_ioctl = reg_ioctl,
};
static struct miscdevice reg_dev =
{
.name = "reg",
.fops = &fops,
.minor = MISC_DYNAMIC_MINOR,
};
static int __init reg_init(void)
{
if(misc_register(®_dev)){
printk(KERN_ERR "Failed to register reg\n");
return -1;
}
printk(KERN_INFO "Success to register reg\n");
return 0;
}
static void __exit reg_exit(void)
{
misc_deregister(®_dev);
reg_unmap();
printk(KERN_INFO "Success to remove reg\n");
}
module_init(reg_init);
module_exit(reg_exit);
MODULE_LICENSE("GPL v2");