当前位置:首页 >综合 >Linux驱动介绍和实例快速入门 通过驱动提供的绍和实例接口

Linux驱动介绍和实例快速入门 通过驱动提供的绍和实例接口

2024-06-26 11:13:08 [百科] 来源:避面尹邢网

Linux驱动介绍和实例快速入门

作者:Android开发编程 系统 Linux 系统调用是动介内核和应用程序之间的接口,而驱动程序是绍和实例内核和硬件之间的接口。它为应用程序屏蔽了硬件的快速细节,故对应用程序而言,入门硬件设备只是动介一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。绍和实例

一、快速驱动简介

Linux的入门驱动在本质上就是一种软件程序,上层软件可以在不了解硬件特性的动介情况下,通过驱动提供的绍和实例接口,和计算机硬件进行通信。快速

系统调用是入门内核和应用程序之间的接口,而驱动程序是动介内核和硬件之间的接口。它为应用程序屏蔽了硬件的绍和实例细节,故对应用程序而言,快速硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。

Linux驱动介绍和实例快速入门 通过驱动提供的绍和实例接口

Linux驱动程序只是内核的一部分,管理着系统的设备控制器和相应的设备。驱动程序,英文名为"Device Driver",全称“设备驱动程序”,是一种可以使计算机和设备通信的特殊程序,相当于硬件的接口,操作系统只有通过这个接口才能控制硬件设备的工作。它主要完成以下几个功能:

Linux驱动介绍和实例快速入门 通过驱动提供的绍和实例接口

  • 对设备初始化和释放
  • 传送数据到硬盘和从硬件读取数据
  • 检测和处理设备出现的错误

二、驱动分类

计算机系统的硬件由CPU、存储器、和外设组成。驱动针对的对象都是存储器和外设。Linux将外设和存储器分为三个基础大类:块设备驱动,字符设备驱动和网络设备驱动。

Linux驱动介绍和实例快速入门 通过驱动提供的绍和实例接口

2.1、字符设备驱动

字符设备是指那些必须以串行顺序访问的设备,字符设备的I/O操作没有通过缓存。字符设备的操作是以字节为基础的,但一次只能执行一个字节的操作。典型的如LCD、串口、LED、蜂鸣器、触摸屏等等。

2.2、块设备驱动

块设备是相对于字符设备定义的,可以以任意顺序进行访问,以块为单位进行操作。块设备驱动的读写都有缓存来支持,且块设备必须能够随机存取。设备的块大小是设备本身设计时定义好的,软件是不能去更改的,不同设备的块大小可以不一样。常见的块设备都是存储类设备,如:硬盘、NandFlash、iNand、SD等等。

2.3、网络设备驱动

网络设备驱动是专为网卡设计的驱动模型,面向数据包的接收和发送而设计的,它并不应对于文件系统的节点。即不对应于/dev目录下的设备文件,应用程序最终用套间字socket完成与网络设备的接口。

除网络设备外,字符设备和块设备都被映射到Linux文件系统的文件和目录,通过文件系统的系统调用接口open(),write(),read(),close()等即可访问字符设备和块设备。块设备比字符设备复杂,在它上面会首先建立一个磁盘/Flash文件系统,如FAT、EXT3、TAFFS、TFFS等,FAT、EXT3、TAFFS、TFF规范了文件和目录在存储介质上的组织。

三、驱动的编译和加载

 Linux设备驱动属于内核的一部分,Linux内核的一个模块可以以两种方式被编译和加载

3.1、编译方式

内部编译:将驱动程序源码放在内核源码目录中进行编译。

外部编译:将驱动程序源码放在内核源码目录外进行编译。

3.2、加载方式

静态加载:编译进uImage中,系统启动时直接加载。

动态加载:编译.ko文件,动态加载驱动模块。

3.3、编译器

x86等架构使用gcc即可,arm嵌入式设备需要使用相关交叉编译工具链。

下面是内核模块的例子:

#include <linux/module.h>    //所有模块都需要的头文件 
#include <linux/init.h> // init&exit相关宏
static int __init hello_init (void)
{
printk("Hello module init\n");
return 0;
}
static void __exit hello_exit (void)
{
printk("Hello module exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LYB");
MODULE_DESCRIPTION("test for linux driver");

分析上述程序,发现一个Linux内核模块需包含模块初始化和模块卸载函数,前者在insmod的时候运行,后者在rmmod的时候运行。初始化与卸载函数必须在宏module_init和module_exit使用前定义,否则会出现编译错误。

初始化与卸载函数必须在宏module_init和module_exit使用前定义,否则会出现编译错误。程序中的:

  • MODULE_LICENSE(“GPL”)用于声明模块的许可证。
  • MODULE_AUTHOR:说明作者信息.。
  • MODULE_DESCRIPTION:对本驱动的描述。

如果要将其直接编译入Linux内核,则需要将源代码文件拷贝入Linux内核源代码的相应路径里,并修改Makefile。

模块初始化函数的任务是为以后调用模块的函数做准备,好像是模块说,:" 我在这里, 这是我能做的”。

模块的退出函数( 例子里是 hello_exit )就在模块被卸载时调用.,它好像告诉内核, "我不 再在那里了, 不要要求我做任何事了”。

 这种编程的方法类似于事件驱动的编程, 但是虽然不是所有的应用程序都是事件驱动的, 每个内核模块都是。另外一个主要的不同, 在事件驱动的应用程序和内核代码之间, 是退出函数: 一个终止的应用程序可以在释放资源方面 懒惰, 或者完全不做清理工作, 但是模块的退出函数必须小心恢复每个由初始化函数建立的东西, 否则会保留一些东西直到系统重启。

编写Makerfile文件来进行编译:

KERN_DIR ?= /usr/src/linux-headers-$(shell uname -r)/        #内核源码目录/usr/src/linux-headers-$(shell uname -r)/
PWD := $(shell pwd)
obj-m := driverTest.ko
all:
make -C $(KERN_DIR) M=$(PWD) modules
clean:
make -C $(KERN_DIR) M=$(PWD) clean

 3.4、驱动加载、卸载及debug

insmod ./hello.ko    // 加载驱动
lsmod // 查看已加载的驱动
lsmod | grep hello // 使用grep检索过滤
demsg // 查看内核打印信息
demsg | grep hello // 使用grep过滤信息
rmmod hello // 卸载驱动


责任编辑:武晓燕 来源: Android开发编程 Linux驱动实例

(责任编辑:百科)

    推荐文章
    热点阅读