原创 一个简单的Linux字符型设备驱动和应用程序的例子

2011-2-25 14:18 4047 3 3 分类: MCU/ 嵌入式
来源:瑞萨单片机论坛

经过近一个月的努力,终于熟悉了Linux下的驱动和应用程序开发流程。
Linux内核支持可插入式模块,驱动程序可以编译在内核中,也可以编译为内核的模块文件。这点和应用程序差不多。常见的驱动程序是作为模块动态加载的,比如声卡,网卡等。而Linux最基本的驱动,如CPU,PCI总线,TCP/IP,APM,VFS等则直接编译到内核文件中。

下面以一个简单的字符型设备驱动为例:

./a.c

#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#define DEVICE_NAME "qq_char"

unsigned int fs_major = 0;


static ssize_t test_read(struct file *file, char *buf, size_t count, loff_t *f_pos);
static int test_open(struct inode *node, struct file *file);
static int test_release(struct inode *inode, struct file *file);

static struct file_operations char_fops = 
{
read: test_read,
open: test_open,
release: test_release
};


static ssize_t test_read(struct file *file, char *buf, size_t count, loff_t *f_pos)
{
int len;
        for(len = count; len > 0; len--){
            put_user(1, buf);   // 将数据放入用户空间的buf中
            buf++;
       }
        return count;
}


// 打开设备
static int test_open(struct inode *node, struct file *file)
{
return 0;
}

// 释放设备
static int test_release(struct inode *inode, struct file *file)
{
return 0;
}


// 注册设备
int init_test(void)
{
int res;

res = register_chrdev(0, DEVICE_NAME, &char_fops);
if(res < 0){
   printk("can't get major name!\n");
   return res;
}

if(fs_major == 0)
   fs_major = res;

        printk("now, i am in kernel mode!\n");
return 0;
}

// 卸载设备
void cleanup_test(void)
{
        printk("now, i am out of kernel\n");
unregister_chrdev(fs_major, DEVICE_NAME);     
}


module_init(init_test);
module_exit(cleanup_test);

编译后,如果是2.6版本,则会生成a.ko
执行insmod a.ko后,内核调用module_init(),从而调用register_chrdev()函数注册该设备。
如果注册成功,则会在/proc/devices下面看到DEVICE_NAME,也就是qq_char,以及主设备号和次设备号,这就是注册了的设备。
如果想卸载设备,则rmmod a,内核调用module_exit(),从而调用unregister_chrdev(),卸载掉该设备。

注册完设备之后,因为/proc是个伪文件系统,/proc/devices下面的qq_char并不是真正的设备文件,所以还要将该设备映射为设备文件。
mknod /dev/qq_char c 253 0
生成设备文件后,可以在/dev下面看到qq_char。好了,到现在为止,我们的设备驱动已经做好了。


下面我们用一个简单的应用程序来测试这个驱动。
./aa.c
#include <stdio.h>
#include <sys/types.h> // pid_t
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>


int main(void)
{
int testdev;
int i;

char buf[10];

testdev = open("/dev/qq_char", O_RDWR);   // 打开设备qq_char

if(testdev == -1){
    printf("cann't open file \n");
    exit(0);
}
   
   printf("now read \n");

   read(testdev, buf, 10);   // 从qq_char读数据到buf中

   printf("read end \n");

   for(i = 0; i < 10; i++){
        printf("%d\n", buf);
   }

   close(testdev);

   return 0;
}

编译,运行该程序,产生如下结果
now read 
read end 
1
1
1
1
1
1
1
1
1
1
成功!

文章评论0条评论)

登录后参与讨论
我要评论
0
3
关闭 站长推荐上一条 /2 下一条