Linux驱动: 字符类设备驱动简介

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。_

2. 本篇目标

本篇目标旨在回答如下问题:

. 如何创建一个字符类设备驱动?
. 字符类设备驱动的fops是如何绑定的?
. 字符类设备驱动接口的调用路径是怎样的?

3. 字符设备驱动

3.1 字符类设备子系统初始化

/* 建立字符类设备的kobj_map */
chrdev_init()
	cdev_map = kobj_map_init(base_probe, &chrdevs_lock)

3.2 建立字符设备驱动

struct xxx_chrdev {
	...
	struct cdev cdev;	  /* Char device structure		*/
} xxx_cdev;

struct file_operations xxx_cdev_fops = {
	.owner =    THIS_MODULE,
	.llseek =   xxx_cdev_llseek,
	.read =     xxx_cdev_read,
	.write =    xxx_cdev_write,
	.unlocked_ioctl = xxx_cdev_ioctl,
	.open =     xxx_cdev_open,
	.release =  xxx_cdev_release,
}
/* 申请字符设备设备号区间 */
alloc_chrdev_region(&dev, MAJOR, 1, "xxx");

/* 注册字符设备到 cdev_map */
cdev_init(&xxx_cdev.cdev, &xxx_cdev_fops);
xxx_cdev.cdev.owner = THIS_MODULE;
xxx_cdev.cdev.ops = &xxx_cdev_fops;
err = cdev_add (&xxx_cdev.cdev, MKDEV(MAJOR, MINOR), 1);

3.3 创建字符设备节点

这里有两种路径为字符设备驱动创建设备节点 /dev/xxx

. 通过 devtmpfs 来创建字符设备节点,之后通知 udevd 等用户态设备事件监听程序,处理设备节
  点添加事件:修改设备节点权限或创建设备节点符号链接;
. 用户空间使用 mknod 等工具,通过 sys_mknod() 系统调用创建字符设备节点。

详情可参考博文 Linux: 设备节点创建移除过程简析

# insmod xxx.ko
# mknod /dev/xxx0 c $major 0
sys_mknod("/dev/xxx0", mode | S_IFCHR, deno)
	sys_mknodat(AT_FDCWD, "/dev/xxx0", mode | S_IFCHR, devno)
		vfs_mknod()
			dir->i_op->mknod(dir, dentry, mode, dev)
				shmem_mknod()
					shmem_get_inode()
						init_special_inode(inode, inode->i_mode, rdev)
							if (S_ISCHR(mode)) { /* 字符类设备的缺省 fops 绑定 */
								inode->i_fop = &def_chr_fops;
								inode->i_rdev = rdev;
							}
		...

这里我们关注的重点是,字符类设备的 fops 设定为 def_chr_fops

3.4 操作字符设备

3.4.1 打开字符设备

/* 通过对字符设备的open调用,将字符类设备的默认fops替换为实际字符设备驱动的fops: def_chr_fops -> xxx_cdev_fops */
sys_open("/dev/xxx0", ...)
	do_sys_open(AT_FDCWD, filename, flags, mode)
		...
		vfs_open(&nd->path, file, current_cred())
			do_dentry_open(file, d_backing_inode(dentry), NULL, cred)
				f->f_op->open() /* f->fop = def_chr_fops */
					chrdev_open()
						/* 从cdev_map找到对应的字符设备对象 */
						obj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
						inode->i_cdev = container_of(kobj, struct cdev, kobj);
						replace_fops(filp, inode->i_cdev->ops); /* 替换字符设备的通用 fops: def_chr_fops -> 设备自定义的 fops */
							filp->f_op->open(inode, filp) /* 调用字符设备自身的open()接口 */
								xxx_cdev_open()

我们可以看到,通过对设备 /dev/xxx0 调用 open(),将字符类通用操作接口 def_chr_fops替换为了字符设备驱动自身的接口,并在最后调用了设备驱动自身的 open 接口。

3.4.2 操作字符设备

/* 字符设备的读、写、ioctl */
sys_read()/sys_write()/sys_ioctl()
	...
	xxx_cdev_read()/xxx_cdev_write()/xxx_cdev_ioctl()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux字符设备驱动Linux内核中的一种设备驱动类型,用于与字符设备进行交互。字符设备是一种按字符流进行输入输出的设备,如串口、终端、打印机等。 在Linux内核中,字符设备驱动通过注册字符设备文件来与用户空间进行通信。它提供了一组操作函数,用于处理读写、打开关闭等操作。 对于字符设备驱动的剖析可以从以下几个方面来理解: 1. 设备注册:字符设备驱动需要通过调用`register_chrdev`函数来注册设备号,并通过`cdev_add`函数向内核注册字符设备驱动。 2. 设备文件操作:字符设备驱动需要实现一些操作函数,如`open`、`read`、`write`、`release`等。这些函数在用户空间通过系统调用来触发,驱动会根据不同的操作进行相应的处理。 3. 设备文件结构:在内核中,每个字符设备都有一个对应的`struct file_operations`结构体,用于存储设备文件操作函数的地址。驱动需要将这个结构体与设备文件关联起来。 4. 中断处理:对于一些特殊的字符设备,如串口接收数据触发中断时,驱动需要实现中断处理函数,并通过注册中断处理程序来响应中断。 5. 设备驱动的通信:字符设备驱动通过读写设备寄存器、共享内存等方式与设备进行通信。驱动需要通过合适的方式与设备进行数据的交互。 总之,字符设备驱动Linux内核中与字符设备交互的重要组成部分。剖析字符设备驱动可以帮助理解驱动的注册、设备文件操作、中断处理等工作原理,从而更好地了解Linux内核的设备驱动机制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值