12th.Linux驱动程序开发

驱动程序

     一个驱动程序,从上到下,可以分为:应用程序,库,内核,驱动程序。开发人员专注于自己熟悉的部分,对于相邻层,只需要了解其接口即可。

  

驱动程序框架

  驱动程序框架大致分为四层

    • 最底层硬件操作程序
    • 创建并填充结构体 
    • 安装函数与卸载函数
    • 修饰安装函数与卸载函数     
 1 /*  【1】最底层驱动函数
 2  *           在函数内实施相应的硬件操作
 3  */
 4 static int first_drv_open(struct inode *inode, struct file *file);
 5 static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos);
 6   
 7 
 8 /*【2】 将驱动程序的函数填充进入结构体
 9  *         让上层可以调用,相应的函数有open,write,read,ioctl.....应用程序里使用open("/dev/xxx")时,就会通过这个结构体,调用open所对应的函数
10  */
11 static struct file_operations first_drv_fops = {
12           .owner      =   THIS_MODULE,    // 这是一个宏,推向编译模块时自动创建的__this_module变量 
13           .open       =   first_drv_open,     
14           .write      =   first_drv_write,       
15   };
16  
17 /* 【3】 驱动程序的安装与卸载函数
18  *       系统加载模块时,会调用到这两个函数
19  */20 int first_drv_init(void);
21 int first_drv_exit(void);
22  
23 
24 /* 【4】修饰封装
25  *         系统使用insmod,rmmod这两个安装卸载的指令时,调用到上面两个函数,所以把上面的init,exit两个函数放在这里
26  */27 module_init(first_drv_init);
28 module_exit(first_drv_exit);
29 MODULE_LICENSE("GPL");

重点函数分析

  first_drv_init(void)函数

 1 int major;
 2 static struct class *firstdrv_class;
 3 static struct class_device    *firstdrv_class_devs;
 4 volatile unsigned long *gpfcon = NULL;
 5 volatile unsigned long *gpfdat = NULL;
 6 
 7 int first_drv_init(void)
 8 {
 9        /*注册驱动程序使用register_chrdev函数 
10          *参数依次为,主设备号,设备名,file_operations结构(即上面定义的结构体)
11          *执行完该函数后,即将三者联系起来
12          *当主设备号设为0时,内核会自动分配主设备号
13          *返回值为主设备号,当返回值为负数时则分配失败
14          */    
15 
16         major=register_chrdev(0,"first_drv",&first_drv_fops);//注册驱动程序
17    
18          /*class_create()、class_device_create()、为自动创建设备目录
19           *安装驱动程序后,需要在/dev目录下创建一个驱动目录,
20           *执行后会自动创建
21           */
22 
23     firstdrv_class = class_create(THIS_MODULE, "firstdrv");
24 
25     firstdrv_class_devs = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xxx");
26 
27 
28        /* 硬件地址重映射操作
29         * 驱动程序与单片机程序不同地方在于,驱动程序不能直接操作寄存器的物理地址
30         * 需要通过ioremap()重新映射一个虚拟地址进行操作
31         */
32     gpfcon = (volatile unsigned long *)ioremap (0x56000050,16);
33 
34     gpfdat = gpfcon+1;
35 
36 
37        //注册完成
38     printk("Setup successfully!")
39         
40     return 0;
41 }

  first_drv_exit(void)函数

 1 int first_drv_exit(void)
 2 {
 3 
 4         /*将注册在内核里的东西移除即可
 5          *卸载驱动、移除/dev设备文件、取消映射
 6          */
 7     unregister_chrdev(major,"first_drv");//卸载驱动程序
 8 
 9     class_device_unregister(firstdrv_class_devs);    
10     class_destroy(firstdrv_class);
11     iounmap(gpfcon);
12     return 0;
13 }

 

 first_drv_open(....)函数 

 1 static int first_drv_open(struct inode *inode, struct file *file)
 2 {
 3         /* 当应用程序执行open("/dev/...")函数时,会调用到这个函数
 4          *  一般在这里写上硬件的初始化操作,而不在init函数里写
 5          *  参数在调用时已经被内核处理了,驱动程序看不到参数
 6          */
 7 
 8     *gpfcon &= ~((0x3<<(4*2))|(0x3<<(5*2))|(0x3<<(6*2)));
 9     *gpfcon |=   ((0x1<<(4*2))|(0x1<<(5*2))|(0x1<<(6*2)));
10     return 0;
11 }

first_drv_write(....)函数  

 1 static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
 2 {
 3     int val;
 4 
 5        /* 写操作程序,需要将传入参数掉出来
 6         * 通过copy_from_user(..)函数
 7         * 参数依次是目标,源,长度
 8         * 将buf拷贝到val,count为长度
 9         */
10     copy_from_user(&val, buf, count);
11 
12        //相应操作
13     if(val==1)
14     {
15         *gpfdat |= (1<<4)|(1<<5)|(1<<6);
16     }
17     else
18     {
19         *gpfdat &= ~((1<<4)|(1<<5)|(1<<6));
20     }
21     
22     return 0;
23 }

编译驱动程序

编译驱动程序,除了这个C文件外,还需要一个MakeFile,代码如下

 1 ##需要依赖编译好的这个驱动程序所使用的内核目录。
 2 KERN_DIR = /work/system/linux-2.6.22.6
 3 
 4 all:
 5     make -C $(KERN_DIR) M=`pwd` modules 
 6 
 7 clean:
 8     make -C $(KERN_DIR) M=`pwd` modules clean
 9     rm -rf modules.order
10 
11 obj-m    += first_drv.o

安装与使用

生成 *.ko文件,即安装文件,在操作系统下安装,使用  insmod xxx.ko   安装驱动。

通过编写好的应用程序调用该驱动即可。

应用程序示例:

 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4 #include <stdio.h>
 5 
 6 /* firsttest on
 7  * firsttest off
 8  */
 9 int main(int argc, char **argv)
10 {
11     int fd;
12     int val=1;
13     fd = open("/dev/xxx",O_RDWR);
14     if(fd<0)
15 
16     {printf("can't open!
");}
17 
18     if(argc!=2)
19     {
20         printf("Usage :
");
21         printf("%s <on|off>
",argv[0]);
22         return 0;
23     }
24 
25     if(strcmp(argv[1],"off")==0)
26     {    
27         val=1;
28     }
29     else 
30         val=0;
31     write(fd, &val, 4);
32     return 0;
33    
34     
35 }
原文地址:https://www.cnblogs.com/asam/p/6433501.html