1、设备结构体
//设备结构体
struct ap3216c_dev {
dev_t devid; /* 设备号 主设备号+次设备号 */
struct cdev cdev; /* cdev 字符设备对象,字符设备驱动的一种结构体类型 */
struct class *class; /* 类 用于创建设备节点,用于表示一组设备的类别。设备类通常包含相似或相关的设备,比如 USB 设备、网络设备 */
struct device *device; /* 设备 用于创建设备节点,则是一个具体的设备对象,它表示一个硬件设备在系统中的实例 */
struct device_node *nd; /* 设备节点,表示设备节点的一种结构体类型。设备节点是设备树中的一个节点。 */
int major; /* 主设备号 ,主设备号表示那种设备(字符、块)次设备号表示具体的设备*/
void *private_data; /* 私有数据 */
unsigned short ir, als, ps; /* 三个光传感器数据 */
};
probe函数
注册设备
注册设备是指将已经创建好的设备对象注册到设备模型中,以便用户空间的程序可以通过设备文件访问该设备
创建设备
创建设备是指在内核中创建一个新的设备对象,并分配该设备所需的内存资源等。这通常是通过调用
kmalloc()
或kzalloc()
等内存分配函数来完成的
static int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
/* 1、构建设备号 */
if (ap3216cdev.major) //如果主设备号存在
{
ap3216cdev.devid = MKDEV(ap3216cdev.major, 0);//次设备号设备为0,合并成设备号
//注册设备号,第二个参数表示注册一个,第三个参数是设备名字(也就是设备节点名字)
register_chrdev_region(ap3216cdev.devid, AP3216C_CNT, AP3216C_NAME);
} else {
//注册设备号,次设备号从0开始
alloc_chrdev_region(&ap3216cdev.devid, 0, AP3216C_CNT, AP3216C_NAME);
//分配主设备号
ap3216cdev.major = MAJOR(ap3216cdev.devid);
}
/* 2、注册设备 */
//
cdev_init(&ap3216cdev.cdev, &ap3216c_ops);//设备操作函数集 ap3216c_ops 和字符设备对象 ap3216cdev.cdev
//该函数调用的作用是将字符设备对象 ap3216cdev.cdev 添加到内核中,并将其与分配的设备号 ap3216cdev.devid 关联起来。
//这样操作系统就能够通过设备号来识别和操作这个字符设备了
cdev_add(&ap3216cdev.cdev, ap3216cdev.devid, AP3216C_CNT);
/* 3、创建类 */
//AP3216C_NAME 的设备类,并将其指针赋值给 ap3216cdev.class,以便后续的设备对象能够使用这个设备类
ap3216cdev.class = class_create(THIS_MODULE, AP3216C_NAME);
//如果创建出错,会报错
if (IS_ERR(ap3216cdev.class)) {
return PTR_ERR(ap3216cdev.class);
}
/* 4、创建设备 */
//,用于在内核中创建一个新的设备对象,并将其注册到设备模型中。
//来创建一个名为 AP3216C_NAME 的设备对象,并将其指针赋值给 ap3216cdev.device。
//该设备对象属于 ap3216cdev.class 所指定的设备类,其设备号为 ap3216cdev.devid,
//此处的 NULL 参数表示设备对象的父设备为顶层总线设备,也就是没有父设备。创建成功后,该设备对象的指针被返回给 ap3216cdev.device
ap3216cdev.device = device_create(ap3216cdev.class, NULL, ap3216cdev.devid, NULL, AP3216C_NAME);
if (IS_ERR(ap3216cdev.device)) {
return PTR_ERR(ap3216cdev.device);
}
ap3216cdev.private_data = client;
return 0;
}