杂项设备实例及Makefile

代码清单:

//复杂的杂项设备例子可以参考内核apm-emulation.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>


//ioctl cmd <->应用空间需要和内核定义一致
#define MISCDEV_MAGIC_CODE  'M'
#define MISCDEV_CLEAR_DATA  _IO(MISCDEV_MAGIC_CODE,1)
#define MISCDEV_READ_DATA   _IOR(MISCDEV_MAGIC_CODE,2,int)
#define MISCDEV_WRITE_DATA  _IOW(MISCDEV_MAGIC_CODE,3,int)

#define MISCDEV_NAME "misc_panda"
#define MISCDEV_DATA_SIZE  0x2000

struct Miscdev_User
{
	char data[MISCDEV_DATA_SIZE];
};

static int miscdev_open(struct inode *inode, struct file *file)
{
	struct Miscdev_User *usr_data = NULL;
	printk("%s\n",__func__);
	usr_data = kzalloc(sizeof(struct Miscdev_User), GFP_KERNEL);
	if(!usr_data)
	{
		return -ENOMEM;
	}
	file->private_data = usr_data;	
	return 0;
	
}
static int miscdev_release(struct inode *inode, struct file *file)
{
	struct Miscdev_User *usr_data = file->private_data;
	file->private_data = NULL;
	kfree(usr_data);
	printk("%s\n",__func__);	
	return 0;
}
static loff_t miscdev_llseek(struct file *file, loff_t offset, int whence)
{
	loff_t ret = offset;
	loff_t pos = 0;
	printk("%s\n",__func__);
	if(!file->private_data)
	{
		return -EINVAL;
	}
	switch(whence){
		case SEEK_SET:
			if(offset < 0 || offset > MISCDEV_DATA_SIZE ){
				ret = -EINVAL; 
				break;
			}
			file->f_pos = offset;
			ret = file->f_pos;
			break;
		case SEEK_CUR:
		case SEEK_END:
			pos = file->f_pos + offset;
			if(pos < 0 || pos > MISCDEV_DATA_SIZE ){
				ret = -EINVAL; 
				break;
			}
			file->f_pos = pos;
			ret = file->f_pos;
			break;
		default:
			ret = -EINVAL;
			break;

	}
	return ret;
}

static ssize_t miscdev_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
{
	int ret = 0;
	loff_t offset = *ppos;
	size_t size = count;
	struct Miscdev_User *usr_data = file->private_data;
	if(!usr_data)
	{
		return -EINVAL;
	}
	printk("%s\n",__func__);
	if(offset >= MISCDEV_DATA_SIZE|| offset < 0 || size < 0){
		return 0;
	}

	if(size > (MISCDEV_DATA_SIZE - offset)){
		size = MISCDEV_DATA_SIZE - offset;
	}

	ret = copy_to_user(buf, usr_data->data + offset, size);//成功,返回0,失败返回未copy成功的数据字节数
	if(ret){
		return -EFAULT;
	}
	else {
		*ppos += size;
		ret = size;
	}	
	return ret;
}

static ssize_t miscdev_write(struct file *file, const char __user *buf,size_t count, loff_t * ppos)
{
	int ret = 0;
	loff_t offset = *ppos;
	size_t size = count;
	struct Miscdev_User *usr_data = file->private_data;
	if(!usr_data)
	{
		return -EINVAL;
	}
	printk("%s\n",__func__);
	if(offset >= MISCDEV_DATA_SIZE || offset < 0 || size < 0){
		return 0;
	}

	if(size > (MISCDEV_DATA_SIZE - offset)){
		size = MISCDEV_DATA_SIZE - offset;
	}

	ret = copy_from_user(usr_data->data + offset,buf, size);//成功,返回0,失败返回未copy成功的数据字节数
	if(ret)
	{
		return -EFAULT;
	}
	else
	{
		*ppos += size;
		ret = size;
	}
	return ret;
}

static long miscdev_ioctl(struct file *file, unsigned int cmd,unsigned long arg)
{
	int err = 0;
	void __user *argp = (void __user *)arg;
	struct Miscdev_User *usr_data = file->private_data;
	if(!usr_data)
	{
		return -EINVAL;
	}
	printk("%s\n",__func__);

	/* Access check of the argument.  Some commands, e.g. create session and process op,
	   needs additional checks.  Those are handled in the command handling functions. */
    if(_IOC_DIR(cmd) & _IOC_READ)
	{
        err = !access_ok(VERIFY_WRITE,argp,_IOC_SIZE(cmd));
	}
    else if(_IOC_DIR(cmd) & _IOC_WRITE)
	{  
		err = !access_ok(VERIFY_READ,argp,_IOC_SIZE(cmd));
	}
    if(err)
	{
        return -EFAULT;
	}
	switch(cmd)
	{
		case MISCDEV_CLEAR_DATA:
			memset(usr_data->data,0,MISCDEV_DATA_SIZE);
			break;
		case MISCDEV_READ_DATA:
			err = copy_to_user(argp, usr_data->data, 100);		
			break;
		case MISCDEV_WRITE_DATA:
			err = copy_from_user(usr_data->data, argp, 100);	
			break;
		default:
			return -EINVAL;
	}
	if(err) 
	{
		return -EFAULT;
	}
	return 0;
}

static const struct file_operations miscdev_fops ={
	.owner = THIS_MODULE,
	.open  = miscdev_open,
	.release = miscdev_release,	
	.llseek = miscdev_llseek,
	.read = miscdev_read,
	.write = miscdev_write,
	.unlocked_ioctl = miscdev_ioctl,
};
	
static struct miscdevice miscdev = {
	.minor = MISC_DYNAMIC_MINOR, //动态分配次设备号
	.name = MISCDEV_NAME,
	.fops = &miscdev_fops,
};

static int __init miscdev_init(void)
{
	int ret = 0;
	//注册一个struct miscdevice 实例,申请次设备号,创建设备文件
	ret = misc_register(&miscdev);
	if(ret < 0)
	{
		printk(KERN_ERR "miscdev:register misc_device failed\n");
		goto out;
	}
	printk(KERN_INFO "miscdev:register misc_device ok\n");
out:
	return ret;
}

static void __exit miscdev_exit(void)
{
	misc_deregister(&miscdev);
	printk(KERN_INFO "miscdev:deregister misc_device ok\n");
}

module_init(miscdev_init);
module_exit(miscdev_exit);
MODULE_DESCRIPTION("MISCDEV Driver");
MODULE_AUTHOR("Kevin D");
MODULE_LICENSE("GPL");

Makefile清单:

ifneq ($(KERNELRELEASE),)

obj-m:=miscdev.o

#miscdev-objs:=file1.o file2.o ##多文件

else

PWD:=$(shell pwd) #当前目录

KERNEL_DIR:=/home/kevin/workspace/driver_test/Hi3519AV100_SDK_V2.0.1.0/osdrv/opensource/kernel/linux-4.9.y/ ##内核绝对路径

ARCH_TYPE=arm  //指定soc架构

CC:=arm-himix200-linux- //指定交叉编译链

all:
    $(MAKE) -C $(KERNEL_DIR) M=$(PWD) ARCH=$(ARCH_TYPE) CROSS_COMPILE=$(CC) modules

    @mkdir -p ./ko

    @cp ./*.ko ./ko/
clean:

    @rm *.symvers *.ko *.o *.mod.c *.order

endif

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值