linux驱动程序设计

xiaoxiao2021-02-28  126

linux驱动程序设计

零碎知识:

一切设备皆文件!(linux的设计理念)

所以,驱动设备在linux系统里就会是一个文件的形式,eg:/dev/znr_dev就是把我的虚拟驱动程序假装一个文件展现

主设备号/从设备号:

主设备号区分不同的驱动程序,相同类型的驱动程序主设备号相同(2个u盘主设备号相同)

从设备号区分具体的设备(2个u盘从设备号不同)

层次关系:

系统调用是内核 和 应用程序 的接口

设备驱动程序是内核 和 硬件 的接口

重要的数据结构:

struct file

表示一个打开的文件,系统每次调用open就打开一次,在内核空间里创建关联的struct file,重要的成员:f_pos, f_op ..

struct inode

表示一个物理文件,记录文件上的物理信息。它和打开的文件结构不一样,一个文件可能有多个file结构体,但只有一个inode结构,在磁盘上存的时候的inode(操作系统文件系统部分)

struct file_operations

open/relase,这是一对,对应应用程序的open,close,这俩个函数会传入inode参数中。

在内核空间性,kmalloc/kfree申请释放空间,

kamlloc(sizeof(XX),GFP_KERNEL)

后面哪个我也不清楚是什么意思,不过需要加

驱动程序:

函数编写的问题:

主体需要实现open,release,这俩个函数是必须实现,并且绑定的

在file_operations结构体中,这俩个函数会传入inode参数。

其他的函数自己按需求写。

常用的read,write,ioctl,读,写,控制

驱动程序运行入口:

static int dev_init()/static void dev_exit()

这俩个函数主要用于注册,删除设备

当注册模块与设备一样的主设备好,名称时,绑定为设备的驱动程序。

这俩个静态函数绑定在宏定义上,

module_init(dev_init); module_exit(dev_exit);

引导驱动程序初始化

再加上程序的信息,就完成了驱动程序的基本功能。

MODULE_DESCRIPTION("znr experiment1 drive"); MODULE_LICENSE("GPL");

驱动程序框架示例:

““c

include

include

include

include

include

define DEV_MAJOR 83

define DEV_INFO 10083_znr

void show_info(void) //show_info()这样写回报错,必须加void { printk(“******\n”); printk(“\t%s\n”DEV_INFO); printk(“******\n\n”); }

size_t dev_read(struct file *file, char *buffer,size_t count, loff_t *f_ops) // f_ops 是偏移量 { copy_to_user(des_buffer, src_buffer, count) //do read }

size_t dev_write(struct file *file, char *buffer,size_t count, loff_t *f_ops) { copy_from_user(des_buffer, src_buffer, count) // do write }

int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data) { //io control }

int dev_open(struct inode inode, struct file file) { //open dev }

int dev_release(struct inode *inode, struct file *file) { //relase dev }

//上下俩种写法都是有的,不过下面兼容性好一点,或者上面这种有时候根本编译不过 struct file_operations dev_operations= { open: dev_open, read: dev_read, write: dev_write, ioctl: dev_ioctl, release: dev_release, };

static struct file_operations fops = { .read = device_read, .write = device_write, .open = device_open, .compat_ioctl = device_ioctl, .release = device_release }; //关于这里详细可以看下面的链接,常用的就是这5个函数

static int dev_init(void) { //注册设备 register_chrdev(dev_main_num, dev_name, &fops); }

static void dev_exit(void) { // 释放设备 unregister_chrdev(dev_main_num, dev_name); }

MODULE_DESCRIPTION(“znr experiment1 drive”); MODULE_LICENSE(“GPL”);

module_init(dev_init); module_exit(dev_exit);

““

内核模块命令+驱动设备命令

内核模块加载 #insmod module_name内核模块卸载 #rmmod module_name查看已加载模块 #lsmod查看系统已加载模块信息 #modinfo创建设备进入点 mknod /dev/device_name type(c , b ) major minor查看设备进入点 ls - l /dev | grep device_name删除设备进入点 rm /dev/device_name

先注册驱动设备,在加载编译好的驱动程序模块,在驱动程序在module_init()向系统注册信息时候,绑定到创建的驱动设备上,实现驱动设备。

以下是示例过程。

““ mknod /dev/znr_dev c 83 0 ls -l /dev | grep znr_dev chmod 777 /dev/znr_dev(可能需要) insmod znr_dev.ko 现在就可以使用了,驱动程序加载好了

rm /dev/znr_dev ““

带参数的内核模块:

module_param(name,type, perm);

在全局变量里定义,然后再用这个宏定义定义。perm是权限的参数,一般用宏定义S_IRUSR即可。

宏MODULE_PARM_DESC() 用来注解该模块可以接收的参数。该宏两个参数:变量名和一个对该变量的描述。

加载内核模块时候,只要在后面跟上参数列表就行,

假设我定义了一个N的全局变量为模块参数,为int类型的,一个name,char*类型的

insmod drive.c N=1024name="my_drive_description"

如果需要声明数组参数:

module_param_array(test,int,num,S_IRUSR);

使用这个,name,type,元素个数,权限

static int test[5] = {1,2,3,4,5}; static int num =5; module_param(num,int,S_IRUSR); module_param_array(test,int,num,S_IRUSR); MODULE_PARM_DESC(test, "test array"); 参数数组的加载方式: insmod test.ko test=6,7,8,9,10 num=5

参考文章/优秀文章:

关于register_chrdev注册字符设备的介绍:

http://book.51cto.com/art/201205/337666.htm

关于Liunx驱动开发比较详细的博客:

http://blog.csdn.net/xinyuwuxian/article/details/9345929

关于file_operations结构体的介绍:

http://blog.csdn.net/zkx1982/article/details/2540401

关于makefile编译的过程:

http://www.cnblogs.com/QuLory/archive/2012/10/23/2736339.html

转载请注明原文地址: https://www.6miu.com/read-28937.html

最新回复(0)