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
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值