Linux驱动学习—杂项设备驱动注册

1、Linux三大设备驱动

字符设备:IO的传输过程是以字符为单位的,没有缓冲。比如I2C,SPI都是字符设备。

块设备:IO传输过程是以块为单位的。跟存储相关的,都属于块设备,比如tf卡。

网络设备:与前两个不一样,是以socket套接字来访问的。

①杂项设备驱动是属于字符设备的一种。可以自动生成设备节点。可以输入cat /proc/misc命令查看有哪些杂项设备。

②杂项设备出来比字符设备代码简单。其他区别是杂项设备的主设备号是相同的,均为是10,次设备号是不同的。主设备号相同就可以节省内核的资源。

③主设备号和次设备号是什么?

设备号包含主设备号和次设备号,主设备号在Linux系统里面 是唯一的,次设备号不一定唯一。

设备号是计算机识别设备的一种方式,主设备号相同的被视为同一类设备。

主设备号比做成电话号码的区号。比如北京的区号是010

次设备号可以比做成电话号码。

主设备号可以通过命令cat /proc/devices来查看

2、杂项设备结构体

①定义在内核源码路径:include\linux/miscdevice.h

struct miscdevice  {
    int minor;
    const char *name;
    const struct file_operations *fops;
    struct list_head list;
    struct device *parent;
    struct device *this_device;
    const struct attribute_group **groups;
    const char *nodename;
    umode_t mode;
};

3、文件操作集结构体

① 文件操作集结构体是在:include\linux/fs.h

struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
    ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
    int (*iterate) (struct file *, struct dir_context *);
    int (*iterate_shared) (struct file *, struct dir_context *);
    unsigned int (*poll) (struct file *, struct poll_table_struct *);
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
    int (*mmap) (struct file *, struct vm_area_struct *);
    int (*open) (struct inode *, struct file *);
    int (*flush) (struct file *, fl_owner_t id);
    int (*release) (struct inode *, struct file *);
    int (*fsync) (struct file *, loff_t, loff_t, int datasync);
    int (*fasync) (int, struct file *, int);
    int (*lock) (struct file *, int, struct file_lock *);
    ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
    unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
    int (*check_flags)(int);
    int (*flock) (struct file *, int, struct file_lock *);
    ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
    ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
    int (*setlease)(struct file *, long, struct file_lock **, void **);
    long (*fallocate)(struct file *file, int mode, loff_t offset,
              loff_t len);
    void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
    unsigned (*mmap_capabilities)(struct file *);
#endif
    ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
            loff_t, size_t, unsigned int);
    int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t,
            u64);
    ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
            u64);
};

注:里面的一个结构体成员都对应一个应用。

②注册杂项设备函数:

extern int misc_register(struct miscdevice *misc);

③注销杂项设备函数:

extern void misc_deregister(struct miscdevice *misc);

4、注册杂项设备的流程

①填充miscdevice这个结构体

②填充file_operations这个结构体

③注册杂项 设备并生产设备节点

5、实验代码

#include <linux/init.h>
#include <linux/module.h>//最基本的文件,支持动态添加和卸载模块
#include <linux/miscdevice.h>//注册杂项设备头文件
#include <linux/fs.h>
#include <linux/uaccess.h>


ssize_t misc_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
{
	printk("misc_read \n");
	return 0;
}

ssize_t misc_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{
	printk("misc_write \n");
	return 0;
}

int misc_open(struct inode *inode, struct file *file)
{
	printk("misc_open \n");
	return 0;
}

int misc_release(struct inode *inode, struct file *file)
{
	printk("misc_release \n");
	return 0;
}

struct file_operations misc_fops={
	.owner = THIS_MODULE,//owner 指针指向的就是你的模块
	.open  = misc_open,
	.release = misc_release,
	.read	= misc_read,
	.write  = misc_write,
};
	
struct miscdevice misc_dev={
	.minor=MISC_DYNAMIC_MINOR,//MISC_DYNAMIC_MINOR动态分配次设备号
	.name = "hello_misc",
	.fops = &misc_fops,
};

static int misc_init(void)
{
	int ret;
	ret = misc_register(&misc_dev);
	if(ret < 0)
	{
		printk("misc register is error \n");
		return ret;
	}
	printk("misc register is succeed \n");
	return 0;
}

static void misc_exit(void)
{
	misc_deregister(&misc_dev);
	printk("misc_exit \n");
}

module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");

makefile:

obj-m += misc.o	#-m的意思是把驱动编译成模块

KDIR := /home/xxx/imx6ull/kernel	#内核路径

PWD?=(shell pwd)	#获取当前目录

all:
    make -C $(KDIR) M=$(PWD) modules

make前设置编译环境变量:

export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-uclibcgnueabihf-

make 就会进入内核源码的路径,然后把当前路径下的代码编译成模块。编译成模块后加载发现生成设备节点:

  • 20
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值