Linux 驱动开发-字符设备驱动

***************************************************************

1。首先书写字符驱动程序。

 /*globalvar.c*/

#include <linux/module.h>   //模块所需的大量符号和函数定义
#include <linux/init.h>     //指定初始化和清楚函数
#include <linux/fs.h>       //文件系统相关的函数和头文件
#include <linux/cdev.h>     //cdev结构的头文件
#include <asm/uaccess.h>    //在内核和用户空间中移动数据的函数

MODULE_LICENSE("GPL");      //指定代码使用的许可证

//文件操作函数的声明
int globalvar_open(struct inode *, struct file *);
int globalvar_release(struct inode *, struct file *);
ssize_t globalvar_read(struct file *, char *, size_t, loff_t *);
ssize_t globalvar_write(struct file *, const char *, size_t, loff_t *);

int dev_major = 200;     //指定主设备号
int dev_minor = 0;      //指定次设备号

struct file_operations globalvar_fops= //将文件操作与分配的设备号相连
{
    owner: THIS_MODULE,                 //指向拥有该模块结构的指针
    open: globalvar_open,
    release: globalvar_release,
    read: globalvar_read,
    write: globalvar_write,
};

struct globalvar_dev                //用来表示我们定义设备的结构
{
    int global_var;                 //这个变量代表要操作的设备
    struct cdev cdev;               //内核中表示字符设备的结构
};

struct globalvar_dev *my_dev;       //设备结构的指针

static void __exit globalvar_exit(void)         //退出模块时的操作
{
    dev_t devno=MKDEV(dev_major, dev_minor);    //dev_t是用来表示设备编号的结构
    cdev_del(&my_dev->cdev);                    //从系统中移除一个字符设备
    kfree(my_dev);                              //释放自定义的设备结构
    unregister_chrdev_region(devno, 1);         //注销已注册的驱动程序
    printk("globalvar unregister success/n");
}

static int __init globalvar_init(void)          //初始化模块的操作
{
    int ret, err;
    dev_t devno=MKDEV(dev_major, dev_minor);

    //动态分配设备号,次设备号已经指定
    ret=alloc_chrdev_region(&devno, dev_minor, 1, "globalvar");

    //保存动态分配的主设备号
    dev_major=MAJOR(devno);

    //根据期望值分配设备号
    //ret=register_chrdev_region(devno, 1, "globalvar");

    if(ret<0)
    {
        printk("globalvar register failure/n");
        globalvar_exit();                      //如果注册设备号失败就退出系统
        return ret;
    }

    else
    {

        printk("globalvar register success/n");
    }


    //为设备在内核空间分配空间
    my_dev=kmalloc(sizeof(struct globalvar_dev), GFP_KERNEL);

    if(!my_dev)
    {
        ret=-ENOMEM;                           //如果分配失败返回错误信息
        printk("create device failed/n");
    }
    else                                       //如果分配成功就可以完成设备的初始化
    {
        my_dev->global_var=0;                        //设备变量初始化为0
        cdev_init(&my_dev->cdev, &globalvar_fops);   //初始化设备中的cdev结构
        my_dev->cdev.owner=THIS_MODULE;              //初始化cdev中的所有者字段
        err=cdev_add(&my_dev->cdev, devno, 1);       //向内核添加这个cdev结构的信息
 
        if(err<0)
            printk("add device failure/n");          //如果添加失败打印错误消息
    }

    return ret;
}


//打开设备文件系统调用对应的操作
int globalvar_open(struct inode *inode, struct file *filp)
{

    struct globalvar_dev *dev;

    //根据inode结构的cdev字段,获得整个设备结构的指针
    dev=container_of(inode->i_cdev, struct globalvar_dev, cdev);

    //将file结构中的private_data字段指向已分配的设备结构
    filp->private_data=dev;

    return 0;

}


//关闭设备文件系统调用对应的操作
int globalvar_release(struct inode *inode, struct file *filp)
{
    return 0;
}

//读设备文件系统调用对应的操作
ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
    //获取指向已分配数据的指针
    struct globalvar_dev *dev=filp->private_data;

    dev->global_var=dev->global_var+1;
   
    //将设备变量值复制到用户空间
    if(copy_to_user(buf, &dev->global_var, sizeof(int)))
    {
        return -EFAULT;
    }

    return sizeof(int);    //返回读取数据的大小
}

//写设备文件系统调用对应的操作
ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
    //获取指向已分配数据的指针
    struct globalvar_dev *dev=filp->private_data;

    //从用户空间复制数据到内核中的设备变量
    if(copy_from_user(&dev->global_var, buf, sizeof(int)))
    {
        return -EFAULT;
    }

    return sizeof(int);    //返回写数据的大小
}

module_init(globalvar_init);        //模块被装载时调用globalvar_init
module_exit(globalvar_exit);        //模块被卸载时调用globalvar_exit

 

 

 

***************************************************************
2。书写Makefile文件

#Makefile
ifneq ($(KERNELRELEASE), )
    obj-m := globalvar.o
else
    KERNELDIR ?= /lib/modules/$(shell uname -r)/build
    PWD := $(shell pwd)

all:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
   
clean:
    $(RM) -f *~ *.o modules.* *.mod.* Module.* *.ko
endif

***************************************************************

3。在终端输入命令> make。加载模块到内核>sudo insmod globalvar.ko.

***************************************************************
4。输入dmesg命令查看模块是否加载内核中

    [ 5891.581723] globalvar register success

***************************************************************

5。终端键入命令>cat /proc/devices ,查看设备号    250 globalvar

 

 

6。sudo mknod /dev/globalvar c 250 0
***************************************************************

7。测试程序

/*test.c*/

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>

int main()
{
    int fd, num;
    
    fd=open("/dev/globalvar", O_RDWR, S_IRUSR|S_IWUSR);     //可读写方式打开设备文件
    if(fd!=-1)
    {
        read(fd, &num, sizeof(int));                        //读取设备变量
        
        printf("The globalvar is %d/n", num);
        printf("Please input the num written to globalvar/n");
        
        scanf("%d", &num);
        write(fd, &num, sizeof(int));                       //写设备变量
        read(fd, &num, sizeof(int));                        //再次读取刚才写的值
        printf("The globalvar is %d/n", num);
        close(fd);                                          //关闭设备文件
    }
    else
    {
        printf("Device open failure/n");
        return -1;
    }
    
    return 0;
}

编译测试程序

gcc -o test test.c

$ ./test
Device open failure
$ ls -l /dev/globalvar
crw-r--r-- 1 root root 250, 0 2010-08-19 09:45 /dev/globalvar
$ sudo chmod 777 /dev/globalvar
$ ls -l /dev/globalvar
crwxrwxrwx 1 root root 250, 0 2010-08-19 09:45 /dev/globalvar
$ sudo chmod 767 /dev/globalvar
$ ls -l /dev/globalvar
crwxrw-rwx 1 root root 250, 0 2010-08-19 09:45 /dev/globalvar
$ sudo chmod 700 /dev/globalvar
$ ls -l /dev/globalvar
crwx------ 1 root root 250, 0 2010-08-19 09:45 /dev/globalvar
$ sudo chmod 777 /dev/globalvar
$ ./test
The globalvar is 1
Please input the num written to globalvar
4
The globalvar is 5
$

**************************************************************

感谢伟哥的帮忙和热心的解答。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jiang_dlut

你的鼓将是我创作的最大动力。。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值