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


将近俩月的时间一直都在朝驱动程序这个方向前进,从刚开始买了一块TQ2440开发板,然后进开始修改、烧写Uboot,修改、裁剪、烧写Linux内核,然后就是一些服务器的搭建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!\n");
	return 0;
}

int Hello_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset)
{
	printk("enter cdd_write!\n");
	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\n");
	return 0;
}

void __exit hello_exit(void)
{
    unregister_chrdev(123, "Hello");	
    printk("Ralink hello driver exited\n");
}

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\n");
	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\n");
}
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地址是tftp服务器的地址。

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、卸载驱动

\

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

相关内容