linux驱动笔记-设备驱动入门

来源:互联网 发布:bec背单词软件 编辑:程序博客网 时间:2024/05/15 23:56

刚学习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>