Linux驱动(一)之最简单的驱动程序

这篇具有很好参考价值的文章主要介绍了Linux驱动(一)之最简单的驱动程序。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、前言

为什么要有驱动?为了防止像我等小菜程序员写应用程序的时候权限过高直接去操作底层设备,给设备造成不可挽回的损失,所以要过度一下,让大牛们将底层封装好,应用开发工程师只需要通过特定的接口来完成特定的功能就可以了。

2、应用

通常情况下,应用开发只需要open一个/dev目录下的文件,然后执行write、read等操作即可。那具体是什么原理呢,以应用程序调用open函数为例,改函数为c库中的函数,实际上会产生中断,将权限交给内核,而内核则会根据相关参数去调用具体驱动程序实现的open函数。

2.1 驱动程序分析

接下来我们来分析一个最简单的字符驱动程序:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>

/*
1. 构造file_operations
2. 填充file_operations
3. 注册file_operations
4. 编写入口和出口
*/

unsigned int major = 146;

int my_dev_open(struct inode * inode, struct file * file)
{
    printk("my_dev_open\n");
    return 0;
}

ssize_t my_dev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
    printk("my_dev_write\n");
    return 0;
}

static const struct file_operations fops = {
	.owner		= THIS_MODULE,
	.open		= my_dev_open,
	.write		= my_dev_write
};

int my_dev_init(void)
{
    printk("my_dev_init\n");
    register_chrdev(major, "mydev", &fops);
    return 0;
}

void my_dev_exit(void)
{
    printk("my_dev_exit\n");
    unregister_chrdev(major, "mydev");
    return;
}

module_init(my_dev_init);
module_exit(my_dev_exit);
MODULE_LICENSE("GPL");

my_dev_init和my_dev_exit函数是我们加载和卸载驱动内核帮我们调用的接口,这两个接口需要分别用module_init和module_exit函数进行修饰。

从头看,我们定义了my_dev_open和my_dev_write函数,并将这两个函数赋值给了file_operations结构体,然后通过register_chrdev函数将该结构体进行注册。注册到底是干啥?看注册函数的三个参数,major, "mydev", &fops,第一个参数是主设备号,什么是设备号呢,就是内核用来区分设备的一个数字,比如鼠标是1,键盘是2,我们在程序中将其写死为了146(没有什么特殊的,随便写的),第二个参数"mydev"是一个名字,第三个参数则是填充了我们自己写的open和write函数的file_operations结构体。整个过程的意思可以这样理解,就是内核维护了一个设备结构体数组,注册函数实现了向数组中添加了一项信息,添加的结构体数组的下标就是主设备号,结构体数组的内容有名字、file_operations等。

多说一下主设备号,执行cat /proc/devices可以查看当前设备,写死的设备号不要与当前设备重复

linux 驱动,linux驱动,linux,驱动开发

将上述代码命令为mydev.c,使用Makefile编译成ko文件,Makefile如下,注意KERN_DIR 要改为你虚拟机或者开发板内核文件目录。

KERN_DIR = /home/02-Kernel/linux-2.6.22.6

all:
	make -C $(KERN_DIR) M=`pwd` modules 

clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order

obj-m	+= mydev.o

2.2 驱动安装

将ko文件拷贝至目标板中,然后执行insmod mydev.ko命令进行安装,可以看到驱动程序中my_dev_init函数添加的打印信息,即my_dev_init接口在执行isnmod命令时得到调用,再次执行 cat /proc/devices可以看到驱动程序完成了注册。

linux 驱动,linux驱动,linux,驱动开发

接下来使用mknod /dev/mydev c 146 0命令创建一个设备节点,该命令的含义:

mknod         // 创建设备节点
/dev/mydev    // 节点名称 
c             // c表示字符设备节点
146           // 主设备号
0             // 次设备号

执行完成后可以ls -l /dev查看创建的设备节点:

linux 驱动,linux驱动,linux,驱动开发

2.3 应用程序分析

编写测试的应用程序代码如下,我们在应用程序中打开了之前创建的设备节点,然后调用write接口向该节点写入了一个数字:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>


int main(int argc, char **argv)
{
    int fd;
    char val = 1;

    fd = open("/dev/mydev", O_RDWR);
    if (fd < 0)
    {
        printf("error, can't open /dev/mydev\n");
        return 0;
    }
    
    write(fd, &val, 1);   
    
    return 0;
}

将程序保存为main.c,直接使用gcc工具进行编译即可:arm-linux-gcc -o main main.c,注意要改为使用自己虚拟机或者开发板的编译工具。

直接运行编译好的程序,可以看到应用程序执行的open和write函数最终调用了我们编写的驱动程序中的open和write接口:

linux 驱动,linux驱动,linux,驱动开发

3、总结

通过一个简单的字符驱动程序讲解了一下linux驱动的框架和调用流程,后续再讲解自动创建字符设备节点等优化内容。文章来源地址https://www.toymoban.com/news/detail-583933.html

到了这里,关于Linux驱动(一)之最简单的驱动程序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 嵌入式Linux驱动开发 02:将驱动程序添加到内核中

    在上一篇文章 《嵌入式Linux驱动开发 01:基础开发与使用》 中我们已经实现了最基础的驱动功能。在那篇文章中我们的驱动代码是独立于内核代码存放的,并且我们的驱动编译后也是一个独立的模块。在实际使用中将驱动代码放在内核代码中,并将驱动编译到内核中也是比较

    2023年04月09日
    浏览(70)
  • Linux 驱动开发基础知识——LED 模板驱动程序的改造:设备树(十一)

     个人名片: 🦁作者简介:学生 🐯个人主页:妄北y 🐧个人QQ:2061314755 🐻个人邮箱:2061314755@qq.com 🦉个人WeChat:Vir2021GKBS 🐼 本文由妄北y原创,首发CSDN 🎊🎊🎊 🐨座右铭:大多数人想要改造这个世界,但却罕有人想改造自己。 专栏导航: 妄北y系列专栏导航: C/C++的基

    2024年02月21日
    浏览(43)
  • 在windows通过VS Code开发Linux内核驱动程序

    最近在看Linux设备驱动程序第三版,为了在windows系统上练手操作,先是下载VMware Workstation安装了Linux系统虚拟机。然后在vscode上编写简单的示例程序,通过ftp把源文件发送到Linux虚拟机后,再在虚拟机上make编译测试内核驱动程序。这样即使是在内核日志中打印个简单的hello w

    2024年02月06日
    浏览(51)
  • Linux设备驱动开发学习笔记(等待队列,锁,字符驱动程序,设备树,i2C...)

    container_of函数可以通过结构体的成员变量检索出整个结构体 函数原型: 内核开发者只实现了循环双链表,因为这个结构能够实现FIFO和LIFO,并且内核开发者要保持最少代码。 为了支持链表,代码中要添加的头文件是linux/list.h。内核中链表实现核心部分的数据结构 是struct li

    2024年01月22日
    浏览(51)
  • 【Linux】按键驱动程序

    【Linux】按键驱动程序 前言: 一、按键驱动程序的背景知识 1.1 查询方式 1.2 休眠-唤醒方式 1.3 poll方式 1.4 异步通知  1.5 总结  二、按键驱动程序的框架 三、按键驱动程序实战 3.1 头文件(button_drv.h) 3.2 驱动程序(button_drv.c) 3.3 驱动程序(button_100ask_imx6ull.c) 3.4 Makefil

    2024年02月10日
    浏览(41)
  • Linux设备驱动程序(一)——设备驱动简介

    这一部分主要是用来介绍 Linux 设备驱动程序的一些基本概念,包括:Linux 设备驱动程序的作用、内核功能的划分、设备和模块的分类以及版本编号。 设备驱动程序就像一个个的“黑盒子”,使某个特定硬件响应一个定义良好的内部编程接口,这些操作完全隐藏了设备的工作

    2024年02月05日
    浏览(87)
  • Linux 设备驱动程序(四)

    Linux 内核设计与实现 深入理解 Linux 内核 Linux 设备驱动程序(一) Linux 设备驱动程序(二) Linux 设备驱动程序(三) Linux 设备驱动程序(四) Linux设备驱动开发详解 深入理解Linux虚拟内存管理     ⇐ ⇒ ⇔ ⇆ ⇒ ⟺ ①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳㉑㉒㉓㉔㉕

    2024年02月16日
    浏览(44)
  • linux的SPI设备驱动程序

            串行外设接口(SPI)是四线总线:MOSI、MISO、串行时钟SCK和片选CS。它常用于连接闪存、AD/DA转换器。主设备生成时钟和管理片选CS,速度可达80MB,远超I2C总线。         SPI设备在内核中表示为struct spi_device{},管理他们的驱动程序的实例是struct spi_driver{}。spi的拓扑结构

    2024年02月13日
    浏览(39)
  • Linux驱动实践:带你一步一步编译内核驱动程序

    记得以前我在开始学习驱动开发的时候,找来很多文章、资料来学习,但是总是觉得缺少了点全局视角。 就好像:我想看清一座山的全貌,但总是被困在一个、又一个山谷中一样。 主要的困惑有 3 点: 每一篇文章的介绍都是正确的,但是如果把很多文章放在一起看,就会

    2023年04月24日
    浏览(49)
  • Linux 内核 ASoC DMA 引擎驱动程序

    Linux 内核 ASoC 框架,在概念上将嵌入式音频系统拆分为多个可复用的组件驱动程序,包括 Codec 类驱动程序、平台类驱动程序和机器类驱动程序。在实现上,机器类驱动程序用 struct snd_soc_card 和 struct snd_soc_dai_link 结构描述,属于平台类驱动程序的 DMA 引擎驱动程序由 struct snd

    2024年02月11日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包