- 字符设备是指在I/O传输过程中以字符单位的进行传输的设备,可以使用与普通文件的相同的文 件操作命令如读、写、打开和关闭等操作。
- 常见的字符设备有led、按键、IIC、SPI、LCD等。
- linux每一个字符设备都具有一个设备号,通过设备号对应相应设备的查找。
设备号:
设备号(MKDEV)分为主设备号(MAJOR)和次设备号(MNOR),主设备号12位,次设备号20位。
设备号的申请:
dev_t major_id;
-
静态申请:major_id = MKDEV(major_id,num);
-
动态申请:alloc_chrdev_region(&devid,0,num_dev,“test”);
会在/poc/devices下面生成对应的节点和节点名称
设备号的销毁:
- unregister_chrdev_region(devid,num_dev);
字符设备的注册和销毁:
struct cdev dev;
关联文件操作集:cdev_init(struct cdev* dev,const struct file_ops);
注册字符设备:cdev_add(struct cdev* dev,dev_t num,unsigned count);
注销字符设备:cdev_del(struct cdev* dev);
设备节点
llinux系统一切皆文件,如果想需要对设备进行操作,则需要对设备的文件进行操作,例如打开、关闭、读、写设备文件。这时我们就需要创建设备节点并在/dev/下产生设备的读写文件
手动创建读写文件:
mknod NAME TYPE MAJOR MINOR
mknod /dev/device_test c 236 0
自动创建节点:
设备文件的自动创建是利用 udev(mdev)机制来实现,多数情况下采用自动创建设备节点 的方式。udev(mdev)可以检测系统中硬件设备状态,可以根据系统中硬件设备状态来创建或者 删除设备文件。
在驱动中首先使用 class_create(…)函数对 class 进行创建,这个类存放于 /sys/class/ 目录下,之后使用 device_create(…)函数创建相应的设备,在进行模块加载时,用户 空间中的 udev 会自动响应 device_create()函数,寻找对应的类从而创建设备节点。
#define class_create(owner, name) \ ({ \
static struct __key;
(owner, name, &__key); \
})
extern void class_destroy(struct class *cls);
struct device * (struct class *cls, struct device *parent, dev_t devt, void *drvdata,
const char *fmt, …);
extern void device_destroy(struct class *cls, dev_t devt);
文件操作集
在进行注册字符设备实验章节中,使用 cdev_init(…)函数对 struct cdev 结构体类型变量和 struct file_operations 结构体类型变量相链接。
struct file_operations 结构体就是把系统调用和驱动程序关联起来的关键数据结构。该结构体的每一个成员都对应着一个系统调用,读取 file_operation 中相应的函数指针,接着把控制权转交给函数,从而完成了 Linux 设备驱动程序 的工作。
static struct file_operations cdev_fops_test=
{
.owner = THIS_MODULE //字段指向本模块,可以避免在模块的操作正在被使用时卸载该模块
.open = chrdev_open //open字段指向 chrdev_open(…)
.read = chrdev_read //read字段指向 chrdev_read(…)
.write = chrdev_write//write字段指向 chrdev_write(…)
.release = chrdev_release //release字段指向 chrdev_write(…)
}
内核空间与用户空间数据
Linux 系统将可访问的内存空间分为了两个部分,一部分是内核空间,一部分是用户空间。 操作系统和驱动程序运行在内核空间(内核态),应用程序运行在用户空间(用户态)。