字符设备驱动

对于linux内核来说,每定义一种概念,就会有对应的一个数据结构来描述(或者说是管理)它。然后相同种类的数据结构一般会被串成链表之类的存在在系统中(个人理解)

一个字符设备驱动的建立

1. 总体流程

描述一个字符设备的数据结构为:struct cdev。

1.1 定义

因此,要创建一个字符设备驱动,首先得创建一个struct cdev
有两种方法(跟我们普通code中实例化一个结构体差不多):

  1. static struct cdev my_cdev;
  2. struct my_dev = cdev_alloc();

1.2 初始化

也类似我们平时初始化一个结构体。(之前一直觉得很驱动模型很复杂总是记不住,其实是没有理解其本质,死记硬背是不行的)
void cdev_init(struct cdev *cdev, const struct file_operation *ops)

1.3 添加到系统中

int cdev_add(struct cdev *p, dev_t dev, unsigned count)

1.4 从系统中删除

void cdev_del(struct cdev *p)

2. 杂项设备

杂项设备的存在主要是为了两个字:方便

杂项设备是字符设备的其中一种,我们利用上面的方法创建出的字符设备要自己指定或在向系统申请一个主设备号,然后还要自己使用mknod命令手动的创建设备节点。
而杂项设备的主设备号系统已经规定好了,就是10;同时,它还会自动创建设备节点。(杂项设备的数据结构的定义struct miscdevice与 普通字符设备的数据结构定义 struct cdev 不同,它多了一个 name 成员来装设备节点的名字)

代码举例

#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/device.h>
#include <linux/fs.h>


#define MY_DEVICE_NAME "han_dev"

static ssize_t
mydrv_open(struct inode *inode, struct file *file)
{
	int major = MAJOR(inode->i_rdev);
	int minor = MINOR(inode->i_rdev);

	printk("mydrv_open\n");
	printk("%s: major=%d, minor=%d\n", __func__, major, minor);
	return 0;

}

static ssize_t
mydrv_release(struct inode *inode, struct file *file)
{
	printk("mydrv_release\n");
	return 0;

}

static ssize_t
mydrv_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	printk("mydrv_read\n");
	return 0;

}

static ssize_t
mydrv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	printk("mydrv_write\n");
	return 0;

}

static ssize_t
mydrv_mmap(struct file *file, struct vm_area_struct *vma)
{
	printk("mydrv_mmap\n");
	return 0;

}

static struct file_operations mydrv_fops  = {
	.owner = THIS_MODULE,
	.open = mydrv_open,
	.release = mydrv_release,
	.read = mydrv_read,
	.write = mydrv_write,
	.mmap = mydrv_mmap,
};

struct miscdevice my_misc_device =   {
	.minor = MISC_DYNAMIC_MINOR,
	.name = MY_DEVICE_NAME,
	.fops = &mydrv_fops,
};

static int __init my_init(void)
{
	int ret;

	ret = misc_register(&my_misc_device);
	if( ret ) {
		printk("Register misc device failed\n");
		return ret;
	}
	printk("Register misc device success\n");
	return 0;
}

static void __exit my_exit(void)
{
	misc_deregister(&my_misc_device);
	printk("removing device\n");
}

module_init(my_init);
module_exit(my_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhouhan");
MODULE_DESCRIPTION("get physpages");
MODULE_ALIAS("han phypages get");

#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

#define DEV_NAME "/dev/han_dev"
int main()
{
	int fd;
	fd = open(DEV_NAME, O_RDWR);

	while(1){
		printf("a = %d",fd);
	}

	return 0;
}

运行结果:
[ 62.088022] Register misc device success
[ 85.643412] mydrv_open
[ 85.676164] mydrv_open: major=10, minor=58
[ 86.790043] mydrv_release
注意,进程退出时,release是会自动调用的

3. 虚拟设备

一些字符设备的内部一般会有一个自己的buffer(FIFO)。芯片内部提供了寄存器来访问这些FIFO;为了提高效率,一般外设芯片支持中断模式,如FIFO有数据到达时,外设芯片通过中断线来告知CPU。
(平时工作中常常用的mailbox不就是这种吗!!)

4. KFIFO

环形缓存类似sipc的fifo

5. 阻塞与非阻塞IO

类似sipc的利用event进行阻塞

6. IO多路复用

poll epoll select

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值