2. 注册Camera设备到内核
任务说明
本案例实现一个最小可用的Camera设备驱动注册模块,目标是将Camera设备注册到Linux内核设备模型,并通过platform驱动框架自动创建设备节点。最终效果:加载模块后,/dev/camera0节点出现,卸载后节点消失。
核心实现
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#define CAMERA_DEVICE_NAME "camera"
#define CAMERA_CLASS_NAME "camera_class"
static dev_t camera_dev_num;
static struct cdev camera_cdev;
static struct class *camera_class;
static struct device *camera_device;
/* 设备节点操作集(最小实现) */
static int camera_open(struct inode *inode, struct file *filp)
{
return 0;
}
static ssize_t camera_read(struct file *filp, char __user *buf,
size_t count, loff_t *pos)
{
return 0;
}
static const struct file_operations camera_fops = {
.owner = THIS_MODULE,
.open = camera_open,
.read = camera_read,
};
/* platform驱动匹配成功后调用 */
static int camera_probe(struct platform_device *pdev)
{
int ret;
/* 1. 动态分配主设备号 */
ret = alloc_chrdev_region(&camera_dev_num, 0, 1, CAMERA_DEVICE_NAME);
if (ret < 0)
return ret;
/* 2. 初始化并添加cdev */
cdev_init(&camera_cdev, &camera_fops);
camera_cdev.owner = THIS_MODULE;
ret = cdev_add(&camera_cdev, camera_dev_num, 1);
if (ret < 0)
goto err_cdev_add;
/* 3. 创建设备类 */
camera_class = class_create(CAMERA_CLASS_NAME);
if (IS_ERR(camera_class)) {
ret = PTR_ERR(camera_class);
goto err_class_create;
}
/* 4. 创建设备节点 /dev/camera0 */
camera_device = device_create(camera_class, &pdev->dev,
camera_dev_num, NULL,
CAMERA_DEVICE_NAME "%d", 0);
if (IS_ERR(camera_device)) {
ret = PTR_ERR(camera_device);
goto err_device_create;
}
dev_info(&pdev->dev, "camera device registered, node: /dev/camera0\n");
return 0;
err_device_create:
class_destroy(camera_class);
err_class_create:
cdev_del(&camera_cdev);
err_cdev_add:
unregister_chrdev_region(camera_dev_num, 1);
return ret;
}
static int camera_remove(struct platform_device *pdev)
{
device_destroy(camera_class, camera_dev_num);
class_destroy(camera_class);
cdev_del(&camera_cdev);
unregister_chrdev_region(camera_dev_num, 1);
dev_info(&pdev->dev, "camera device removed\n");
return 0;
}
static struct platform_driver camera_platform_driver = {
.probe = camera_probe,
.remove = camera_remove,
.driver = {
.name = CAMERA_DEVICE_NAME,
},
};
module_platform_driver(camera_platform_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kernel Camera Course");
MODULE_DESCRIPTION("Minimal camera device registration example");
编译与加载
创建Makefile:
obj-m := camera_device.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
执行编译与加载:
make
sudo insmod camera_device.ko
ls -l /dev/camera0
验证方法
- 设备节点存在:
ls -l /dev/camera0应显示字符设备,主设备号为动态分配值(如240+),次设备号为0。 - 设备模型注册:
cat /sys/devices/virtual/camera_class/camera0/dev应输出主设备号:0。 - 卸载清理:
sudo rmmod camera_device后,/dev/camera0消失,dmesg尾部出现camera device removed日志。
若insmod后/dev/camera0未出现,执行dmesg | tail查看错误信息,常见原因为设备号分配失败或class_create返回错误。