linux驱动笔记-设备驱动入门
刚学习linux的时候我很迷惑,不清楚一个个设备是如何和系统联系起来的,最初我做了很多的无用功。我是学电子的,从大一就开始接触到单片机,但是我学了它之后我还没有一点点计算机系统的概念。
下面对学习的快速入门经验(希望大家不要再像我一样走了弯路):
对linux有一个最为初步的了解
linux就是一个计算机系统,和windows7类似!那它的最为主要的原因是:开源(网上可以下载到它的源代码);如果以后要用到它,那就请多去了解下它。用上它之后,基本上每天都是和命令行打交道(现在的X图形界面虽好看,但个人认为不会shell是不行的)。原因是shell是一个非常基本的东西,它是直接和内核打交道的,用它的效率会提高很多。
我们要做的工作简单来说:那就是做一个设备而这个设备是运行的一个操作系统,系统通过一些外部设备完成一些功能,系统对任务进行调度。
那么我们要做的事也就是要做一个驱动程序去操控设备,那么设备如何明白这是一个驱动呢?那就需要这个驱动程序在结构、编译、执行上都有不同于一般程序的操作。系统提供一些IO接口,如file_operations结构体(一个字符驱动重要的结构体),结构中有很多指针函数,这些函数可以指向你的驱动程序中的某个函数。下面就以字符驱动为讲解,
字符驱动程序要完成的工作如下:
15 #define HELLO_MAJOR_NR 126 //device major number
16 #define DEVICE_NAME "hello" //device name
为你的设备的创建一个file_operations结构,如:
static struct file_operations hello_fops=
{
open: hello_open,
unlocked_ioctl: hello_ioctl,
.release = hello_release,
};
到系统中注册驱动(使用函数register_chrdev(HELLO_MAJOR_NR主设备号, DEVICE_NAME驱动名称,&hello_fops)
使用你写的控制函数对设备进行操作。如:你写了一个hello_ioctl(struct file *filp,unsigned int cmd, unsigned long arg)。
如果你是新手,现在可能会问如何调用这个控制函数呢?
要完成注册后会在系统的/dev下面产生一个设备驱动对应的文件。文件名就是hello,
还有一个不行不说一下的东东——
驱动的安装insmod hello.ko
所以就必須要有一个安装时运行的函数module_init(); register_chrdev()向系统注册就是在这里完的。
卸载时运行的函数module_exit();
驱动的卸载rmmod hello.ko
我们的驱动程序的主体就算是完成了,可控制函数到底在哪里用呢?
答案:应用程序中。
应用程序中,用open()打开/dev/hello得到文件指针,再使用ioctl()对设备进行操作,操作的完成就是用的通过参数的传递。
下面给出驱动源码:
#include<linux/module.h>
#include<linux/sched.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/ioctl.h>
#include<linux/fs.h>
#include<linux/types.h>
#include<linux/mm.h>
#include "hello.h"
static int hello_open(struct inode *inode,struct file *filp);
static int hello_release(struct inode *inode,struct file *filp);
static long hello_ioctl(struct file *filp,unsigned int cmd,unsigned long arg);
#define HELLO_MAJOR_NR 126 //device major number
#define DEVICE_NAME "hello" //device name
#define MAX_PORT 1 // 1 devices
static struct file_operations hello_fops=
{
open: hello_open,
unlocked_ioctl: hello_ioctl,
.release = hello_release,
};
int __init hello_init(void)
{
int result;
result = register_chrdev(HELLO_MAJOR_NR, DEVICE_NAME,&hello_fops); //register facilities(¿¿)
if(result<0) {
printk(KERN_ERR DEVICE_NAME ":Unable to get major %d\n", HELLO_MAJOR_NR);
return result;
}
printk(KERN_INFO DEVICE_NAME ":init OK, return %d\n",result);
return 0;
}
void __exit hello_cleanup(void)
{
unregister_chrdev(HELLO_MAJOR_NR, DEVICE_NAME);
}
static int hello_open(struct inode *inode, struct file *filp)
{
// M0D_INC_USE_COUNT;
return 0;
}
static int hello_release(struct inode *inode, struct file *filp)
{
// MOD_DEC_USE_COUNT;
return 0;
}
static long hello_ioctl(struct file *filp,unsigned int cmd, unsigned long arg)
{
//参数arg没有用
switch(cmd) {
case 0:完成事件0
case 1:完成事件1
.....
}
return 0;
}
module_init(hello_init);
module_exit(hello_cleanup);
MODULE_LICENSE("GPL");
下面给出应用程序源码:
#include<stdlib.h>
#include<stdio.h>
#include<fcntl.h>
int main()
{
int fd;
fd = open("/dev/hello",O_RDONLY);
if(fd < 0) {
printf("open error: %d\n",fd);
return 0;
}
num = ioctl(fd,0,0);
if(num == -1) {
printf("ioctl errno\n");
exit(1);
}
ioctl(fd,0,0); //事件0
ioctl(fd,1,0); //事件1
close(fd);
exit(0);
}
由于水平有限,若有什么错误,欢迎大家指正!<xueyang1122@gmail.com>