0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Openwrt开发指南 第16章 驱动开发之字符设备驱动程序框架

嵌入式大杂烩 来源:嵌入式大杂烩 作者:嵌入式大杂烩 2023-06-30 09:01 次阅读

1 字符设备驱动程序框架简介

我们在学习 C 语言的时候,知道每个应用程序的入口函数,即第一个被执行的函数是 main函数,那么,我们自己的驱动程序,哪个函数是入口函数呢?

在写驱动程序的时候,如果函数的名字可以任意取,常常为 xxxx_init(),当实现好这个 xxxx_init()函数以后,内核其实并不知道这个就是我们驱动的入口函数,因此我们要想办法告诉内核,我们的入口函数是哪个?我们通过 module_init()函数来告诉内核,具体如下。

module_init(RT5350_drv_init);

通过上面的修饰以后, RT5350_drv_init()这个函数就变成了我们的驱动程序的入口函数了。当然,有入口函数,自然还需要一个出口函数,我们通过 module_exit()函数来告诉内核,具体如下。

module_exit(RT5350_drv_exit);

从上一章中,我们知道,应用程序是通过 open、read、write ...函数来和我们的驱动程序进行交互的,那么我们的驱动程序是怎么给应用程序提供这些接口的呢?我们在写驱动程序的时候,我们首先需要定义出一个 file_operations 结构体,该结构体便是驱动和应用程序交互的接口。具体定义如下。

struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long,loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long,loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long,
unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *,
size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t,
unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len);
};

我们的驱动程序要给应用程序提供哪些接口,就只需要填充相应的成员即可。比如我们想提供 open、read、write 这三个接口,就应该如下定义。

static struct file_operations RT5350_drv_fops = {
.owner = THIS_MODULE, /*这是一个宏,推向编译模块时自动创建的__this_module 变量 */
.open = RT5350_drv_open,
.read = RT5350_drv_read,
.write = RT5350_drv_write,
};

当 file_operations 结构体定义、设置好以后,我们只需要通过 register_chrdev()函数将该机构图注册进内核即可。

2 字符设备驱动程序框架实现

经过前面部分的讲解,相信大家一定对如何写一个自己的驱动程序,有所感悟了。接下来,给大家一个简单的驱动程序的例子,可以用于作为框架模板,以后的驱动都可以基于该驱动进行修改。

#include < linux/mm.h >
#include < linux/miscdevice.h >
#include < linux/slab.h >
#include < linux/vmalloc.h >
#include < linux/mman.h >
#include < linux/random.h >
#include < linux/init.h >
#include < linux/raw.h >
#include < linux/tty.h >
#include < linux/capability.h >
#include < linux/ptrace.h >
#include < linux/device.h >
#include < linux/highmem.h >
#include < linux/crash_dump.h >
#include < linux/backing-dev.h >
#include < linux/bootmem.h >
#include < linux/splice.h >
#include < linux/pfn.h >
#include < linux/export.h >
#include < linux/io.h >
#include < linux/aio.h >
#include < linux/kernel.h >
#include < linux/module.h >

#include < asm/uaccess.h >

#define DEVICE_NAME     "RT5350"  /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
#define RT5350_MAJOR       0       /* 主设备号 */

static struct class *RT5350_drv_class;

static int RT5350_drv_open(struct inode *inode, struct file *file)
{
	printk("%s:Hello RT5350
", __FUNCTION__);	// printk用于驱动中添加打印,用法和应用程序中的printf一样

	return 0;
}

static ssize_t RT5350_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	printk("%s:Hello RT5350
", __FUNCTION__);	// printk用于驱动中添加打印,用法和应用程序中的printf一样

	return 0;
}

static ssize_t RT5350_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
{
	printk("%s:Hello RT5350
", __FUNCTION__);	// printk用于驱动中添加打印,用法和应用程序中的printf一样

	return 0;
}

/* 这个结构是字符设备驱动程序的核心
** 当应用程序操作设备文件时所调用的open、read、write等函数,
** 最终会调用这个结构中指定的对应函数
**/
static struct file_operations RT5350_drv_fops = {
	.owner  	= THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
	.open   	= RT5350_drv_open,     
	.read	= RT5350_drv_read,	   
	.write	= RT5350_drv_write,	   
};

int major;
/*
** 执行insmod命令时就会调用这个函数 
*/
static int __init RT5350_drv_init(void)
{
	/* 注册字符设备
	** 这步是写字符设备驱动程序所必须的
	** 参数为主设备号、设备名字、file_operations结构;
	** 这样,主设备号就和具体的file_operations结构联系起来了,
	** 操作主设备为RT5350_MAJOR的设备文件时,就会调用RT5350_drv_fops中的相关成员函数
	** RT5350_MAJOR可以设为0,表示由内核自动分配主设备号
	*/
	major = register_chrdev(RT5350_MAJOR, DEVICE_NAME, &RT5350_drv_fops);
	if (major < 0)
	{
		printk(DEVICE_NAME " can't register major number
");
		return major;
	}

	/*
	** 以下两行代码用于创建设备节点,是必须的。
	** 当然,如果不写这两行,那么就必须在linux系统命令行中通过mknod这个命令来创建设备节点
	*/
	/* 创建类 */
	RT5350_drv_class = class_create(THIS_MODULE, "RT5350");
	/* 类下面创建设备节点 */
	device_create(RT5350_drv_class, NULL, MKDEV(major, 0), NULL, "RT5350");		// /dev/RT5350

	/*
	** 打印一个调试信息
	*/
	printk("%s:Hello RT5350
", __FUNCTION__);	// printk用于驱动中添加打印,用法和应用程序中的printf一样

	return 0;
}

/*
 * 执行rmmod命令时就会调用这个函数 
 */
static void __exit RT5350_drv_exit(void)
{
	unregister_chrdev(major, "RT5350");		// 与入口函数的register_chrdev函数配对使用
	device_destroy(RT5350_drv_class, MKDEV(major, 0));	// 与入口函数的device_create函数配对使用
	class_destroy(RT5350_drv_class);	// 与入口函数的class_create函数配对使用

	printk("%s:Hello RT5350
", __FUNCTION__);	// printk用于驱动中添加打印,用法和应用程序中的printf一样
}

/* 这两行指定驱动程序的初始化函数和卸载函数 */
module_init(RT5350_drv_init);
module_exit(RT5350_drv_exit);

/* 描述驱动程序的一些信息,不是必须的 */
MODULE_AUTHOR("BruceOu");
MODULE_VERSION("0.1.0");
MODULE_DESCRIPTION("RT5350 FIRST Driver");
MODULE_LICENSE("GPL");
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7534

    浏览量

    128881
  • 驱动程序
    +关注

    关注

    19

    文章

    770

    浏览量

    47248
  • 函数
    +关注

    关注

    3

    文章

    3911

    浏览量

    61313
  • 驱动开发
    +关注

    关注

    0

    文章

    129

    浏览量

    12010
  • OpenWrt
    +关注

    关注

    10

    文章

    117

    浏览量

    38881
收藏 人收藏

    评论

    相关推荐

    ArmSoM系列板卡 嵌入式Linux驱动开发实战指南字符设备驱动

    字符设备驱动 本章,我们将学习字符设备使用、字符设备
    的头像 发表于 04-10 09:53 611次阅读
    ArmSoM系列板卡 嵌入式Linux<b class='flag-5'>驱动</b><b class='flag-5'>开发</b>实战<b class='flag-5'>指南</b> 之 <b class='flag-5'>字符</b><b class='flag-5'>设备</b><b class='flag-5'>驱动</b>

    迅为RK3568开发驱动开发指南-输入子系统

    迅为RK3568开发驱动开发指南-输入子系统
    的头像 发表于 02-23 15:11 211次阅读
    迅为RK3568<b class='flag-5'>开发</b>板<b class='flag-5'>驱动</b><b class='flag-5'>开发指南</b>-输入子系统

    RT-Thread设备驱动开发指南基础篇—以先楫bsp的hwtimer设备为例

    RT-Thread设备驱动开发指南》书籍是RT-thread官方出品撰写,系统讲解RT-thread IO设备驱动
    的头像 发表于 02-20 16:01 834次阅读
    RT-Thread<b class='flag-5'>设备</b><b class='flag-5'>驱动</b><b class='flag-5'>开发指南</b>基础篇—以先楫bsp的hwtimer<b class='flag-5'>设备</b>为例

    Banana Pi BPI-W3 RK3588平台驱动调试篇 [ PCIE篇二 ] - PCIE的开发指南

    Banana Pi BPI-W3 RK3588平台驱动调试篇 [ PCIE篇 ] - PCIE的开发指南(二)
    的头像 发表于 11-02 09:24 323次阅读
    Banana Pi BPI-W3 RK3588平台<b class='flag-5'>驱动</b>调试篇 [ PCIE篇二 ] - PCIE的<b class='flag-5'>开发指南</b>

    移动设备中的重力感应驱动程序开发

    电子发烧友网站提供《移动设备中的重力感应驱动程序开发.pdf》资料免费下载
    发表于 10-30 11:23 0次下载
    移动<b class='flag-5'>设备</b>中的重力感应<b class='flag-5'>驱动程序</b><b class='flag-5'>开发</b>

    Linux系统驱动开发字符设备虚拟设备实验

    本系列图文教程均以全志H3开发板为实验板设计,字符设备驱动开发是最基础的驱动
    发表于 08-07 16:16 332次阅读
    Linux系统<b class='flag-5'>驱动</b><b class='flag-5'>开发</b>之<b class='flag-5'>字符</b><b class='flag-5'>设备</b>虚拟<b class='flag-5'>设备</b>实验

    MegaRAID SAS设备驱动程序安装用户指南

    电子发烧友网站提供《MegaRAID SAS设备驱动程序安装用户指南.pdf》资料免费下载
    发表于 07-27 15:40 4次下载
    MegaRAID SAS<b class='flag-5'>设备</b><b class='flag-5'>驱动程序</b>安装用户<b class='flag-5'>指南</b>

    Openwrt开发指南 第25章 配置OpenWrt支持网络摄像头

    Openwrt开发指南 第25章 配置OpenWrt支持网络摄像头
    的头像 发表于 07-13 08:56 1598次阅读
    <b class='flag-5'>Openwrt</b><b class='flag-5'>开发指南</b> 第25章 配置<b class='flag-5'>OpenWrt</b>支持网络摄像头

    Openwrt开发指南 第24章 配置开发板支持U盘

    Openwrt开发指南 第24章 配置开发板支持U盘
    的头像 发表于 07-13 08:55 1384次阅读
    <b class='flag-5'>Openwrt</b><b class='flag-5'>开发指南</b> 第24章 配置<b class='flag-5'>开发</b>板支持U盘

    Openwrt开发指南 第22章 Openwrt串口的使用2

    在上一章中,我们成功的让驱动程序支持了串口 2,并且做了简单的测试。接下来,我们就为串口 2 添加一个应用程序,从而实现 Wi-Fi 串口。实现过程非常简单,首先进入 OpenWrt 系统源码,然后运行 make menucon
    的头像 发表于 07-05 09:09 3174次阅读
    <b class='flag-5'>Openwrt</b><b class='flag-5'>开发指南</b> 第22章 <b class='flag-5'>Openwrt</b>串口的使用2

    Openwrt开发指南 第20章 驱动开发之LED应用程序

    在前面的章节中, 我们成功的写出了我们自己的驱动程序, 并且向应用程序提供了 open、ioctl 两个接口,那么接下来我们就来编写应用程序,调用这些接口。
    的头像 发表于 07-03 09:02 2138次阅读
    <b class='flag-5'>Openwrt</b><b class='flag-5'>开发指南</b> 第20章 <b class='flag-5'>驱动</b><b class='flag-5'>开发</b>之LED应用<b class='flag-5'>程序</b>

    Openwrt开发指南 第18章 驱动开发字符设备应用程序

    在前面的章节中, 我们成功的写出了我们自己的驱动程序, 并且向应用程序提供了 open、read、write 三个接口,那么接下来我们就来编写应用程序,调用这些接口。
    的头像 发表于 07-02 09:21 2134次阅读
    <b class='flag-5'>Openwrt</b><b class='flag-5'>开发指南</b> 第18章 <b class='flag-5'>驱动</b><b class='flag-5'>开发</b>之<b class='flag-5'>字符</b><b class='flag-5'>设备</b>应用<b class='flag-5'>程序</b>

    Openwrt开发指南 第17章 驱动开发字符设备驱动程序

    首先将 RT5350_drv 文件夹传到 OpenWrt 源码的chaos_calmer/package/kernel 目录下。然后进入 OpenWrt 源码的顶层目录,执行 make menuconfig。
    的头像 发表于 07-02 09:20 2527次阅读
    <b class='flag-5'>Openwrt</b><b class='flag-5'>开发指南</b> 第17章 <b class='flag-5'>驱动</b><b class='flag-5'>开发</b>之<b class='flag-5'>字符</b><b class='flag-5'>设备</b><b class='flag-5'>驱动程序</b>

    Openwrt开发指南 第15章 驱动开发字符设备驱动程序之概念介绍

    从上到下,一个软件系统可以分为:应用程序、库、操作系统(内核)、驱动程序开发人员可以专注于自己熟悉的部分,对于相邻层,只需要了解它的接口,无需关注它的实现细节。
    的头像 发表于 06-30 09:00 2181次阅读
    <b class='flag-5'>Openwrt</b><b class='flag-5'>开发指南</b> 第15章 <b class='flag-5'>驱动</b><b class='flag-5'>开发</b>之<b class='flag-5'>字符</b><b class='flag-5'>设备</b><b class='flag-5'>驱动程序</b>之概念介绍

    Openwrt开发指南 第2章 OpenWrt开发环境搭建

    ,并烧写到设备中;另外,嵌入式设备的资源并不足以用来开发软件。所以需要用到交叉开发模式:在主机上编辑、编译软件,然后在目标板上运行、验证程序
    的头像 发表于 06-27 09:09 4537次阅读
    <b class='flag-5'>Openwrt</b><b class='flag-5'>开发指南</b> 第2章 <b class='flag-5'>OpenWrt</b><b class='flag-5'>开发</b>环境搭建