新字符设备驱动原理

       分配和释放设备号

int major;                                // 主设备号
int minor;                                // 次设备号
dev_t devid;                              // 设备号

if(major)                                 // 定义主设备号
{
    devid = MKDEV(major, 0);                     // 构建次设备号

    // 起始设备号:devid
    // 申请数量:1
    // 设备名:text 
    register_chrdev_region(devid, 1, "test");    // 注册设备号
}
else                                      // 未定义主设备号
{
    alloc_chrdev_region(&devid, 0, 1, "text");    // 申请设备号
    major = MAJOR(devid);                         // 获取主设备号
    minor = MINOR(devid);                         // 获取次设备号
}


unregister_chrdev_region(devid, 1);               // 注销设备号

 

       新的字符设备注册方法

                 字符设备结构

// linux-5.5.4\linux-5.5.4\include\linux\cdev.h
/* SPDX-License-Identifier: GPL-2.0 */

#ifndef _LINUX_CDEV_H
#define _LINUX_CDEV_H

//...

struct cdev                            // 字符设备结构体
{
    struct kobject kobj;
    struct module *owner;
    const struct file_operations *ops;    // 字符设备文件操作函数集合
    struct list_head list;
    dev_t dev;                        // 设备号
    unsigned int count;
}__randomize_layout;

//...

#endif

          cdev_init 函数

struct cdev testcdev;

static struct file_operations test_fogs =    // 设备操作函数
{
    .owner = THIS_MODULE;
    //...
};

testcdev.owner = THIS_MODULE;

// 初始化cdev变量:testcdev
// 字符设备文件操作函数集合:test_fops
cdev_init(&testcdev,&test_fops);    //初始化cdev结构体变量

 

 

 


自动创建设备节点

    mdev 机制

         

     创建和删除类

 

// linux-5.5.7/include/linux/device.h
/* This is a #define to keep the compiler from merging different
 * instances of the __key variable */
#define class_create(owner, name)		\
({						\
	static struct lock_class_key __key;	\
	__class_create(owner, name, &__key);	\
})


// linux-5.5.7/drivers/base/class.c
/**
 * class_create - create a struct class structure
 * @owner: pointer to the module that is to "own" this struct class
 * @name: pointer to a string for the name of this class.
 * @key: the lock_class_key for this class; used by mutex lock debugging
 *
 * This is used to create a struct class pointer that can then be used
 * in calls to device_create().
 *
 * Returns &struct class pointer on success, or ERR_PTR() on error.
 *
 * Note, the pointer created here is to be destroyed when finished by
 * making a call to class_destroy().
 */
struct class *__class_create(struct module *owner, const char *name,
			     struct lock_class_key *key)
{
	struct class *cls;
	int retval;

	cls = kzalloc(sizeof(*cls), GFP_KERNEL);
	if (!cls) {
		retval = -ENOMEM;
		goto error;
	}

	cls->name = name;
	cls->owner = owner;
	cls->class_release = class_create_release;

	retval = __class_register(cls, key);
	if (retval)
		goto error;

	return cls;

error:
	kfree(cls);
	return ERR_PTR(retval);
}
EXPORT_SYMBOL_GPL(__class_create);

    创建设备

// linux-5.5.7/drivers/base/core.c
/**
 * device_create - creates a device and registers it with sysfs
 * @class: pointer to the struct class that this device should be registered to
 * @parent: pointer to the parent struct device of this new device, if any
 * @devt: the dev_t for the char device to be added
 * @drvdata: the data to be added to the device for callbacks
 * @fmt: string for the device's name
 *
 * This function can be used by char device classes.  A struct device
 * will be created in sysfs, registered to the specified class.
 *
 * A "dev" file will be created, showing the dev_t for the device, if
 * the dev_t is not 0,0.
 * If a pointer to a parent struct device is passed in, the newly created
 * struct device will be a child of that device in sysfs.
 * The pointer to the struct device will be returned from the call.
 * Any further sysfs files that might be required can be created using this
 * pointer.
 *
 * Returns &struct device pointer on success, or ERR_PTR() on error.
 *
 * Note: the struct class passed to this function must have previously
 * been created with a call to class_create().
 */
struct device *device_create(struct class *class, struct device *parent,
			     dev_t devt, void *drvdata, const char *fmt, ...)
{
	va_list vargs;
	struct device *dev;

	va_start(vargs, fmt);
	dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
	va_end(vargs);
	return dev;
}
EXPORT_SYMBOL_GPL(device_create);

 


设置文件私有数据

// 设备结构体
struct test_dev
{
    dev_t devid;              //设备号
    struct cdev cdev;         //cdev
    struct class *class;      //类
    struct device *device;    // 设备
    int major;                //主设备号
    int minor;                //次设备号
};

struct test_dev testdev;

// open函数
static int test_open(struct inode *inode, struct file *filp)
{
    // 设置私有数据
    filp -> private_data = &testdev;
    return 0;
}