• 【Linux驱动】第一个驱动程序


            将近俩月的时间一直都在朝驱动程序这个方向前进。从刚開始买了一块TQ2440开发板,然后进開始改动、烧写Uboot。改动、裁剪、烧写Linux内核。然后就是一些server的搭建tftp、samba等,还有交叉编译环境的搭建,然后是改动驱动程序,一直到如今写了自己的第一个驱动程序。明确了编写驱动程序的流程,尽管仅仅是类似于Helloworld的简单的不能再简单的程序。可是这也算是站在了神奇的驱动程序的家门口了吧。!大笑

          回忆这将近倆个多月的时间,遇到过各种各样的问题。多亏了队友的支持和帮助,当遇到问题的时候一起解决,一起讨论,这要比自己一个人默默的在网上搜解决方式要靠谱的多啊。由于每一个人对同一知识的认识是不同的,思维方法也是不同的。对于同一问题产生的解决的方法也是不同的。一起讨论的时候就可能产生新的解决方法。因此。驱动这条路上要多交往一些这种好友。才干走得更远。

    同一时候,还认为要真的有一份绝不轻言放弃的品质,耐下心。一次一次的去尝试,然后反思总结解决这个问题的办法。

    未来要走的路还远之又远,遇到的困难更会不计其数。但这正是成为大牛的必经道路。跨过了这道坎。你就向大牛迈进了一步。借用漩涡鸣人的一句话告诫自己:我但是要成为火影的人。怎么能输在这里!!!

        扯淡到此结束。进入正题:

    (1)驱动程序Hello.c的源码:

    #include <linux/miscdevice.h>    
    #include <linux/delay.h>    
    #include <asm/irq.h>
    #include <linux/kernel.h>    
    #include <linux/module.h>
    #include <linux/delay.h>
    #include <linux/unistd.h>
    #include <linux/string.h>
    #include <linux/fcntl.h>
    #include <asm/uaccess.h>
    #include <linux/kdev_t.h>
    #include <linux/fs.h>
    #include <linux/init.h>
    #include <linux/version.h>
    
    #include <linux/kernel.h>
    #include <linux/interrupt.h>
    #include <linux/sched.h>
    #include <linux/device.h>    
    
    MODULE_LICENSE("Dual BSD/GPL");
    
    int Hello_read(struct inode *inode, struct file *filp)
    {
    	printk("enter cdd_open!
    ");
    	return 0;
    }
    
    int Hello_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset)
    {
    	printk("enter cdd_write!
    ");
    	return 0;
    }
    
    static struct file_operations io_dev_fops = {   
        .owner = THIS_MODULE,  
        .read = Hello_read,
        .write = Hello_write,  
    }; 
    
    int __init hello_init(void)
    {
        register_chrdev(123, "Hello",&io_dev_fops);	
        printk("Ralink gpio driver initialized
    ");
    	return 0;
    }
    
    void __exit hello_exit(void)
    {
        unregister_chrdev(123, "Hello");	
        printk("Ralink hello driver exited
    ");
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    
    驱动是靠近底层,与硬件和内核打交道的。内核通过驱动将请求转化为命令操作硬件设备。因此驱动程序向上要给内核提供接口,向下要可以读写硬件的寄存器,可以控制硬件。驱动首先要告诉内核它的存在。也就是注冊。

    代码中的注冊函数在以下这个函数中,同一时候这个函数就是这个驱动的入口。当我们利用insmod命令挂在驱动的时候,首先会进入到这个函数中:

    int __init hello_init(void)
    {
        register_chrdev(123, "Hello",&io_dev_fops);	
        printk("Ralink gpio driver initialized
    ");
    	return 0;
    }
    register_chrdev(123, "Hello",&io_dev_fops);123为主设备号“Hello”是在/proc/devices以下显示的该驱动的名称。io_dev_fops是一个file_operations结构体

    static struct file_operations io_dev_fops = {   
        .owner = THIS_MODULE,  
        .read = Hello_read,
        .write = Hello_write,  
    }; 
    这个结构体相当于一个连接,通过它能够找到在这个驱动中的其它的函数Hello_read、Hello_write(这两个函数分别相应着应用层程序中的函数write、read。当在应用层调用这两个函数,就会通过一系列的动作找到相应的驱动程序中的Hello_read、Hello_write函数),这函数里面就能够写一些对于硬件的操作,由于我写的是最简单的驱动程序。因此没有对于写硬件的操作。

    以下是出口函数,当使用rmmod卸载函数时会进入到以下这个函数中

    void __exit hello_exit(void)
    {
        unregister_chrdev(123, "Hello");	
        printk("Ralink hello driver exited
    ");
    }
    unregister_chrdev(123, "Hello");是注销驱动程序的注冊信息的。

    (2)測试程序:

    #include <stdio.h>   
    #include <stdlib.h>   
    #include <unistd.h>      
    #include <sys/types.h>     
    #include <sys/stat.h>   
    #include <fcntl.h>     
      
    
    int main()  
    {  
        int fd;   
        int value=1;   
        fd=open("/dev/hello",O_RDWR); 
        if (fd<0)  
        {  
            printf("open led_driver error");  
            exit(1);  
        }
        write(fd,&value,4); 
        return 0;  
     }  

    (3)測试

    1、利用tftp将文件下载到开发板上


    后面的IP地址是tftpserver的地址。

    2、查看一下/proc/devices,没有此驱动程序要申请的主设备号123


    3、利用insmod命令安装驱动后再次查看,有主设备号123 Hello,说明驱动成功安装。而且输出Ralink gpio driver initialized。说明进入到驱动的初始化函数中


    4、測试驱动

    执行test发现出现错误:


    查找原因是由于在/dev下没有设备节点/dev/Hello


    利用mknod新建设备节点并再次查看/dev。有设备节点hello


    再次执行test:


    測试程序调用驱动成功,输出enter cdd_write,说明成功进入调用到Hello_write函数!

    5、卸载驱动


    到此为止,第一个驱动程序编写成功!




  • 相关阅读:
    NetScaler ‘Counters’ Grab-Bag!
    NetScaler + Wireshark = A Perfect Combination!
    What’s That NetScaler Reset Packet?
    Give NetScaler a “Tune-Up”
    51Nod 1080 两个数的平方和(数论,经典题)
    51Nod 1289 大鱼吃小鱼(模拟,经典好题)
    1082 与7无关的数(思维题,巨坑)
    51Nod 1003 阶乘后面0的数量(数学,思维题)
    2017广东工业大学程序设计竞赛决赛 题解&源码(A,数学解方程,B,贪心博弈,C,递归,D,水,E,贪心,面试题,F,贪心,枚举,LCA,G,dp,记忆化搜索,H,思维题)
    后缀数组(一堆干货)
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/6893845.html
Copyright © 2020-2023  润新知