linux驱动程序设计

linux驱动程序设计

零碎知识:

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

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

主设备号/从设备号:

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

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

层次关系:

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

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

layer

重要的数据结构:

  • 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

reationship.png

先注册驱动设备,在加载编译好的驱动程序模块,在驱动程序在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

你可能感兴趣的:(linux)