linux字符驱动的一般init初始化流程

static int __init chardev_init(void)
{
	//int value = 0;
	//value = register_chrdev(200,"chard",&chardev_fops);
    //分配
	if(newchar_dev.major){
		newchar_dev.devid = MKDEV(newchar_dev.major, 0);
		register_chrdev_region(newchar_dev.devid,NEWCHARDEV_CNT,NEWCHARDEV_NAME);
	
	}else{
		alloc_chrdev_region(&newchar_dev.devid,0, NEWCHARDEV_CNT,NEWCHARDEV_NAME);
		newchar_dev.major = MAJOR(newchar_dev.devid);
		newchar_dev.minor = MINOR(newchar_dev.devid);
	}
	printk("--%s--%d,newchadev.major %d\n",__func__,__LINE__,newchar_dev.major);	
    //初始化 注册cdev
	newchar_dev.cdev.owner = THIS_MODULE;
	cdev_init(&newchar_dev.cdev, &chardev_fops);

	cdev_add(&newchar_dev.cdev,newchar_dev.devid,NEWCHARDEV_CNT);

     //创建类
	newchar_dev.class = class_create(THIS_MODULE, NEWCHARDEV_NAME);

	newchar_dev.device = device_create(newchar_dev.class,NULL, newchar_dev.devid,NULL,NEWCHARDEV_NAME);


	
	printk("--%s--%d,init sucess \n",__func__,__LINE__);
	return 0;
}

alloc_chrdev_region()实质上申请了初始化了char_device_struct的结构体。

static struct char_device_struct {
    struct char_device_struct *next;
    unsigned int major;
    unsigned int baseminor;
    int minorct;
    char name[64];
    struct cdev *cdev;        /* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];

在字符设备驱动开发的入门教程中,最常见的就是用device_create()函数来创建设备节点了,但是在之后阅读内核源码的过程中却很少见device_create()的踪影了,取而代之的是device_register()与device_add(),将device_create()函数展开不难发现:其实device_create()只是device_register()的封装,而device_register()则是device_add()的封装。

struct device *device_create(struct class *class, struct device *parent,
                 dev_t devt, void *drvdata, const char *fmt, ...)
{
    ......
    dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
    ......
    return dev;
}

struct device *device_create_vargs(struct class *class, struct device *parent,
                   dev_t devt, void *drvdata, const char *fmt,
                   va_list args)
{
    ......

    dev->devt = devt;
    dev->class = class;
    dev->parent = parent;
    dev->release = device_create_release;
    dev_set_drvdata(dev, drvdata);
    ......
    retval = device_register(dev);
    ......
}

int device_register(struct device *dev)
{
    device_initialize(dev);
    return device_add(dev);

device_add()会在/sys目录对应设备目录下创建uevent属性节点,应用层的udev则会根据uevent来创建/dev目录下的设备节点,这里关于udev的部分不再赘述,我们继续分析device_create()、device_register()、device_add()三个函数在实际运用中的区别。

以一个简单的led设备字符设备驱动为例,下面分别用device_create()、device_register()、device_add()三个函数来创建设备节点“/dev/led”:

class_create() 和 device_create()有什么关系呢??

在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点,当然前提条件是用户空间移植了udev。什么事udev??请查看“  收集 3个介绍uedv 网址资料    ”

内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。

参考链接:https://blog.csdn.net/zifehng/article/details/73844845

参考链接:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值