Chinaunix首页 | 论坛 | 博客
  • 博客访问: 350201
  • 博文数量: 159
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 182
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-02 10:42
文章分类

全部博文(159)

文章存档

2015年(18)

2014年(132)

2013年(9)

分类: LINUX

2013-11-02 14:05:39

字符设备驱动程序源码

#include
#include
#include
#include
/*定义一个字符设备对象*/
static struct cdev mycdev;
/*字符设备节点的设备号*/
static dev_t ndev;
static int mycdev_open(struct inode *nd, struct file *filp)
{
    int major = MAJOR(nd->i_rdev);
    int minor = MINOR(nd->i_rdev);
    printk("mycdev_open, major=%d, minor=%d\n", major, minor);
    return 0;
}

static ssize_t mycdev_read(struct file *f, char __user * u, size_t sz, loff_t * off)
{
    printk("In the mycdev_read() function!\n");
    return 0;
}

static int mycdev_release(struct inode *nd, struct file *filp)
{
    printk("In the mycdev_release() function!\n");
    return 0;
}

/*字符设备驱动程序中非常关键的一个数据结构 struct file_operations*/
struct file_operations chr_ops = {
    .owner = THIS_MODULE,
    .open = mycdev_open,
    .read = mycdev_read,
    .release = mycdev_release,
};

/*模块的初始化函数*/
static int mycdev_init(void)
{
    int ret = 0;
    /*初始化字符设备对象 */
    cdev_init(&mycdev, &chr_ops);
    /*分配设备号 */
    ret = alloc_chrdev_region(&ndev, 0, 1, "mycdev");
    if (ret < 0)
        return ret;
    printk("mycdev_init():major=%d, minor=%d\n", MAJOR(ndev), MINOR(ndev));
    /*将字符设备对象 mycdev 注册进系统 */
    ret = cdev_add(&mycdev, ndev, 1);
    if (ret < 0)
        unregister_chrdev_region(ndev, 1);
    return ret;
}

static void mycdev_exit(void)
{
    printk("Removing mycdev module...\n");
    /*将字符设备对象 mycdev 从系统中卸载掉 */
    cdev_del(&mycdev);
    /*释放分配的设备号 */
    unregister_chrdev_region(ndev, 1);
}

module_init(mycdev_init);
module_exit(mycdev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("bilaizi");
MODULE_DESCRIPTION("A char device driver as an example");

可以参照下面这个简单的 Makefile 文件来编译上述的模块:

# Makefile2.6
obj-m :=mycdev.o # 产生mycdevmod 模块的目标文件
CURRENT_PATH := $(shell pwd) #模块所在的当前路径
LINUX_KERNEL := $(shell uname -r) #Linux内核源代码的当前版本
LINUX_KERNEL_PATH := /usr/src/kernels/$(LINUX_KERNEL)/ #Linux内核源代码的绝对路径
all:
    make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules #编译模块
clean:
    make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean #清理
应用程序源码mycdevtest.c
#include

#include
#include
#define CHR_DEV_NAME "/dev/mycdev"
int main()
{
    int ret;
    char buf[32];
    int fd = open(CHR_DEV_NAME, O_RDONLY | O_NDELAY);
    if (fd < 0) {
        printf("open file %s failed!\n", CHR_DEV_NAME);
        return -1;
    }
    read(fd, buf, 32);
    close(fd);
    return 0;
}
可以用 gcc 来生成该应用程序的可执行文件 mycdevtest:
[root@bilaizi 桌面]# gcc -o mycdevtest mycdevtest.c
具体操作步骤如下
[root@
bilaizi 桌面]# insmod mycdev.ko
[root@bilaizi 桌面]# dmesg
mycdev_init():major=247, minor=0
通过上面 dmesg 的输出信息,我们知道 alloc_chrdev_region 函数给内核模块 mycdev
.ko

分配的主设备号为 247,次设备号为 0。根据这个设备号信息用 mknod 命令在系统的/dev 目录下为
该模块生成一个新的设备文件节点:
[root@bilaizi 桌面]#mknod /dev/mycdev c 247 0
如果一切正常,那么在/dev 目录下就会产生一个新的设备文件节点“/dev/mycdev”可以用 ls 命令来仔细观察一下它:
[root@bilaizi 桌面]# ls -l /dev/mycdev
crw-r--r--. 1 root root 247, 0 11月  2 20:38 /dev/mycdev
上面 ls 命令的输出反映出了设备节点“/dev/chr_dev”的如下一些关键信息:
“crw-r--r--”中的字符“c”表明这是个字符设备文件,247 是该设备节点的主设备号,次设备号则
是 0,这跟我们的预期是完全一致的。
有了对应的设备文件之后,现在可以运行我们的应用程序了:
[root@bilaizi 桌面]#./mycdev
[root@bilaizi 桌面]#dmesg -c
mycdev_open, major=247, minor=0
In the mycdev_read() function!
In the mycdev_release() function!
对比前面内核模块 mycdev.ko 的源码,读者应该知道上述两行的输出分别来自内核模块中的
mycdev_open、mycdev_read 和mycdev_release 函数,虽然在这个示例程序中它们几乎没做任何事情,但是我
们见证了应用程序成功调用到了设备驱动程序实现的函数,这正是我们所预期的目标。
















阅读(1097) | 评论(1) | 转发(0) |
0

上一篇:没有了

下一篇:单链表实现

给主人留下些什么吧!~~

7大爷2013-11-04 09:27:00

不错不错!