嵌入式Linux驱动开发基础-3 LED驱动框架
1:回顾字符设备驱动框架

1.2如何编写驱动程序
- 确定主设备号,也可以让内核分配
- 定义自己的 file_operations 结构体
- 实现对应的 drv_open/drv_read/drv_write 等函数,填入 file_operations 结构体
- 把 file_operations 结构体告诉内核:register_chrdev
- 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数
- 有入口函数就应该有出口函数:卸载驱动程序时,出口函数调用unregister_chrdev
- 其他完善:提供设备信息,自动创建设备节点:class_create,device_create
1.3:对于 LED 驱动,构建什么样的接口?

1.4LED 驱动能支持多个板子的基础:分层思想
1:把驱动拆分为通用的框架(leddrv.c)、具体的硬件操作(board_X.c):

2:以面向对象的思想,改进代码,抽象出一个结构体:


2:代码编写
2.1:代码主体逻辑图

2.1.1:把 LED 的操作抽象出一个 led_operations 结构体
首先看看 led_opr.h,它定义了一个 led_operations 结构体,把 LED 的操作抽象为这个结构体:
#ifndef _LED_OPR_H
#define _LED_OPR_H
struct led_operations {
int (*init) (int which); /* 初始化LED, which-哪个LED */
int (*ctl) (int which, char status); /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
};
struct led_operations *get_board_led_opr(void);
#endif
2.1.2 驱动程序的上层:file_operations 结构体
首先查看入口函数:
/* 4. 把file_operations结构体告诉内核:注册驱动程序 */
/* 5. 谁来注册驱动程序啊?一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
static int __init led_init(void)
{
int err;
int i;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
major = register_chrdev(0, "100ask_led", &led_drv); /* /dev/led */
led_class = class_create(THIS_MODULE, "100ask_led_class");
err = PTR_ERR(led_class);
if (IS_ERR(led_class)) {
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "100ask_led");
return -1;
}
for (i = 0; i < LED_NUM; i++)
device_create(led_class, NULL, MKDEV(major, i), NULL, "100ask_led%d", i); /* /dev/100ask_led0,1,... */
p_led_opr = get_board_led_opr();
return 0;
}
查看file_operations 结构体的成员函数::
p_led_opr->ctl(minor, status); p_led_opr->init(minor); 调用 led_operations 结构体中对应的函数。
/* write(fd, &val, 1); */
static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int err;
char status;
struct inode *inode = file_inode(file);
int minor = iminor(inode);
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = copy_from_user(&status, buf, 1);
/* 根据次设备号和status控制LED */
p_led_opr->ctl(minor, status);
return 1;
}
static int led_drv_open (struct inode *node, struct file *file)
{
int minor = iminor(node);
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
/* 根据次设备号初始化LED */
p_led_opr->init(minor);
return 0;
}
/* 2. 定义自己的file_operations结构体 */
static struct file_operations led_drv = {
.owner = THIS_MODULE,
.open = led_drv_open,
.read = led_drv_read,
.write = led_drv_write,
.release = led_drv_close,
};
static int led_drv_close (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
2.1.3:board_demo.c函数
static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */
{
printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);
return 0;
}
static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
{
printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off");
return 0;
}
static struct led_operations board_demo_led_opr = {
.init = board_demo_led_init,
.ctl = board_demo_led_ctl,
};
struct led_operations *get_board_led_opr(void)
{
return &board_demo_led_opr;
}
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)