首页 > 技术文章 > 嵌入式Linux驱动学习之路(二十七)字符设备驱动的另一种写法

ynxf 2016-11-14 21:26 原文

之前讲的字符设备驱动程序,只要有一个主设备号,那么次设备号无论是什么都会和同一个 struct file_operations 结构体对应。

而本节课讲的是如何在设备号相同的情况下,让不同的次设备号对应不同的  struct file_operations 结构体。

在本次的驱动程序中,打开/dev/hello0 、 /dev/hello1  调用的是hello_open函数。打开/dev/hello2 调用的是 hello2_open 函数。打开其他次设备号的文件,则是打开失败。

驱动程序代码:

/*************************************************************************
    > File Name: hello.c
    > Author: 
    > Mail: 
    > Created Time: 2016年11月14日 星期一 20时28分50秒
 ************************************************************************/
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h> #include <linux/wait.h> #include <linux/mutex.h> #include <linux/io.h> #include <linux/cdev.h> #include <linux/fs.h> /* 确定主设备号 唯一 */ static int major; /* 第二种设备的函数 */ static int hello2_open( struct inode *inode, struct file *file ) { printk("hello_open2\n"); return 0; } /* 第一种设备的函数 */ static int hello_open( struct inode *inode, struct file *file ) { printk("hello_open\n"); return 0; } /* 第一种设备的结构体 */ static struct file_operations hello_ops = { .owner = THIS_MODULE, .open = hello_open, }; /* 第二种设备的结构体 */ static struct file_operations hello2_ops = { .owner = THIS_MODULE, .open = hello2_open, }; static struct cdev hello_cdev; static struct cdev hello2_cdev; static struct class *cls; static int hello_init(void) { dev_t devid; if(major) //如果已经有了设备号则不再申请,如果没有则自动申请一个 { devid = MKDEV(major, 0); //次设备号从0开始计算 register_chrdev_region(devid,2,"hello"); //有两个设备文件与之对应 } else { alloc_chrdev_region(&devid, 0, 2,"hello"); //次设备号从0开始计算,有两个设备文件与之对应 major = MAJOR(devid); } cdev_init( &hello_cdev, &hello_ops ); cdev_add( &hello_cdev, devid, 2); //有两个设备文件与之对应 即次设备号为0~1的设备文件调用 hello_ops 中的函数 /* 因为上面的已经有了主设备号,这里肯定也是有主设备号,所以不用判断是否要去申请了 */ devid = MKDEV(major, 2); //次设备号从0开始计算 register_chrdev_region(devid,1,"hello2"); //有一个设备文件与之对应 cdev_init( &hello2_cdev, &hello2_ops ); cdev_add( &hello2_cdev, devid, 1 ); //有一个设备文件与之对应 即次设备号为2的设备文件调用 hello2_ops 中的函数 cls = class_create(THIS_MODULE,"hello"); class_device_create(cls,NULL,MKDEV(major,0),NULL,"hello0"); class_device_create(cls,NULL,MKDEV(major,1),NULL,"hello1"); class_device_create(cls,NULL,MKDEV(major,2),NULL,"hello2");
   class_device_create(cls,NULL,MKDEV(major,3,NULL,"hello3");
return 0; } static void hello_exit(void) { class_device_destroy(cls,MKDEV(major,0)); class_device_destroy(cls,MKDEV(major,1)); class_device_destroy(cls,MKDEV(major,2));
   class_device_destroy(cls,MKDEV(major,3)); class_destroy(cls); cdev_del(
&hello_cdev); unregister_chrdev_region(MKDEV(major,0),1); cdev_del(&hello2_cdev); unregister_chrdev_region(MKDEV(major,2),1); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL");

 测试程序代码:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int main( int argc, char **argv )
{
    int fd;
    if(argc != 2)
        return 0;
    fd = open(argv[1],O_RDWR);
    
    if(fd<0)
        printf("open failed\n");
    else
        printf( "can open\n" );

    return 0;
}

 

推荐阅读