Linux设备驱动(2)字符设备

设备号

设备号由主设备号和次设备号组成。linux下,一切设备皆文件,所有的设备都能在/dev目录下找到相应的文件。这些文件除了名字不一样以外,还每个设备文件都有不一样的设备号;
一般地,主设备号对应一个类型的驱动设备,之所以有次设备号,它是用来驱动同类型的设备。如串口,所有的串口共用一个主设备号,每个串口有不同的次设备号。

dev_t类型用来保存设备编号(包含主设备号和次设备号),实际上是一个32位整数,12位用来表示主设备号,后20位表示次设备号。

#define MINORBITS   20
#define MINORMASK   ((1U << MINORBITS) - 1)

//提取主设备号
#define MAJOR(dev)  ((unsigned int) ((dev) >> MINORBITS))
//提取次设备号
#define MINOR(dev)  ((unsigned int) ((dev) & MINORMASK))
//生成设备号
#define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))

设备号的分配和释放

静态分配

/**
 * register_chrdev_region() - register a range of device numbers
 * @from: the first in the desired range of device numbers; must include
 *        the major number.
 * @count: the number of consecutive device numbers required
 * @name: the name of the device or driver.
 *
 * Return value is zero on success, a negative error code on failure.
 */
int register_chrdev_region(dev_t from, unsigned count, const char *name)

指定从设备号from开始,申请count个设备号,在/proc/devices中的名字为name

动态分配

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

动态申请从次设备号baseminor开始的count个设备号,在/proc/devices中的名字为name,并通过dev指针把分配到的设备号返回给调用函数者。

释放

void unregister_chrdev_region(dev_t from, unsigned count)

设备注册

字符设备struct cdev

struct cdev {
    struct kobject kobj;
    struct module *owner;//一般初始化为THIS_MODULE
    const struct file_operations *ops;//文件操作结构体
    struct list_head list;
    dev_t dev;//设备号
    unsigned int count;//添加的设备个数
};

注册的三个步骤:
1)分配cdev;
2)初始化cdev;
3)添加cdev;

分配

直接定义struct cdev test_cdev;

或者动态分配
truct cdev* test_cdev;
test_cdev = cdev_alloc();

初始化

/**
 * cdev_init() - initialize a cdev structure
 * @cdev: the structure to initialize
 * @fops: the file_operations for this device
 *
 * Initializes @cdev, remembering @fops, making it ready to add to the
 * system with cdev_add().
 */
void cdev_init(struct cdev *cdev, const struct file_operations *fops)

这个函数干了两件事情:
1)内核自己填充了结构体中list和kobj的内容
2)把传入的文件操作结构体也填充进去

一般的,还要手工定义结构体成员owner。

添加

将cdev结构体与设备号关联起来:

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

参数:
cdev:指定要被添加的cdev结构体;
dev:对应的设备号
count:从设备号dev开始添加count个设备.

函数干了也两件事:
1)把cdev结构体中还没填充的两个成员dev和count按照传入参数赋值。
2)把cdev结构体中传入内核,这样内核就知道对应设备号和具体的文件操作结构体了。

删除

void cdev_del(struct cdev *p)

你可能感兴趣的:(Linux设备驱动,linux)