本文在上一篇文章学习的基础上,文章地址如下:
本文来学习 编写 LED灯驱动框架代码。
上一篇文章创建了 2_led工程,设置了 可能会调用到的 Linux内核源码路径。初步编写了 Led灯驱动模块的加载与卸载代码框架。
这里在 前面代码实现的基础上,继续进行代码编写。
这里可以参考 Linux内核源码中驱动模块的代码实现 进行编写。可以在( NXP官方提供的) Linux 内核源码中找一个包含 驱动模块注册与卸载的代码实现。
注册字符设时这里选择使用 register_chrdev()函数,注册字符设备时可以参考 Linux内核源码中的驱动模块如何注册。例如,这里我参考drivers/block/paride/pg.c 文件中注册字符设备时 register_chrdev() 函数调用:
err = register_chrdev(major, name, &pg_fops);
卸载字符设备时调用:
unregister_chrdev(major, name);
或者直接找到 函数定义处,进行编写。 register_chrdev()函数在 内核源码 根目录下 /include/linux/fs.h 文件中。
结构体file_operations中函数集,根据需求实现相应的函数,不需要全部实现。
这里 Led灯驱动实验,我们这里只需要设置电平,也就是写入数据,不需要读数据。所以, file_operations结构体不需要进行 read函数实现。
参考 结构体file_operations 关于 函数操作集 的框架实现:
static const struct file_operations pg_fops = {
.owner = THIS_MODULE,
.read = pg_read,
.write = pg_write,
.open = pg_open,
.release = pg_release,
.llseek = noop_llseek,
};
static ssize_t pg_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
............................
returncopy + hs;
}
static ssize_t pg_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
............................
}
static int pg_open(struct inode *inode, struct file *file)
{
............................
}
static int pg_release(struct inode *inode, struct file *file)
{
............................
}
led.c 驱动框架代码如下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#define LED_DEVICE_NUMBER 200 //Led的主设备号
#define LED_NAME "led" //Led灯的名字
//打开Led设备
static int led_open(struct inode *inode, struct file *file)
{
return 0;
}
// 向Led设备写数据
static ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
return 0;
}
//关闭/释放设备
static int led_release(struct inode *inode, struct file *file)
{
return 0;
}
static const struct file_operations led_fops=
{
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
.release = led_release,
};
//Led驱动模块入口函数
static int __init led_init(void)
{
int ret = 0;
printk("led_init!\r\n");
//注册字符设备
ret = register_chrdev(LED_DEVICE_NUMBER, LED_NAME, &led_fops);
if(ret < 0)
{
printk("led device register failed!\r\n");
return -EIO;
}
return 0;
}
//Led驱动模块出口函数
static void __exit led_exit(void)
{
printk("led_exit!\r\n");
//卸载字符设备
unregister_chrdev(LED_DEVICE_NUMBER, LED_NAME);
}
module_init(led_init); //入口
module_exit(led_exit); //出口
MODULE_LICENSE("GPL"); //模块 licence
MODULE_AUTHOR("lingxuewu"); //模块作者