在ubuntu下编写验证字符设备驱动

1,准备工作

  1.   uname -r  查看电脑版本信息
  2.        apt-get  install  linux-source  安装相应版本的linux内核

 

2,编写驱动程序

    Global CharDev.c

/* GlobalCharDev.c */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>

#include <asm/uaccess.h>


#define DEV_NAME "GlobalChar"

static ssize_t GlobalRead(struct file *, char *, size_t, loff_t *);
static ssize_t GlobalWrite(struct file *, const char *, size_t,loff_t *);

static int char_major = 0;
static int GlobalData = 0; /* "GlobalChar"设备的全局变量 */

/* 初始化字符设备驱动的 file_operations 结构体 */
struct file_operations globalchar_fops = 
{
    .read = GlobalRead,
    .write = GlobalWrite
};

/* 模块初始化 */
static int __init GlobalChar_init(void)
{
    int ret;

    ret = register_chrdev(char_major, DEV_NAME, &globalchar_fops);/* 注册设备驱动,_driver_char_misc.c 第290行参考  */
    if(ret < 0 )
        printk(KERN_ALERT "GlobalChar Reg Fail\n");
    else
        {
        printk(KERN_ALERT "GlobalChar Reg Success\n");
        char_major = ret;
        printk(KERN_ALERT "Major = %d\n", char_major);
        }
    return ret;
}

/* 模块卸载函数 */
static void __exit GlobalChar_exit(void)
{
    unregister_chrdev(char_major, DEV_NAME); /* 注销设备驱动 */
    return;
}

/* 模块驱动读函数 */
static ssize_t GlobalRead(struct file *file, char *buf, size_t len, loff_t *off)
{
    if (copy_to_user(buf, &GlobalData ,sizeof(int)))  
    {
        /* 从内核复制 GlobalData 到用户空间*/
        return -EFAULT;
    }
    return sizeof(int);
}

/* 模块驱动写函数 */
static ssize_t GlobalWrite(struct file *file, const char *buf, size_t len, loff_t *off)
{
    if (copy_from_user(&GlobalData, buf, sizeof(int)))
    {
        /* 从用户复制 GlobalData 到内核 */
        return -EFAULT;
    }
    return sizeof(int);

}


module_init(GlobalChar_init);
module_exit(GlobalChar_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("dongjin");

 

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

  Make file

ifneq ($(KERNELRELEASE),)    
    obj-m := GlobalCharDev.o
else
    
# KERNELDIR ?= /lib/modules/$(shell uname -r)/build
    KERNELDIR ?= /usr/src/linux-headers-$(shell uname -r)       //这两个都可以

    PWD := $(shell pwd)

default:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:
    rm -rf rm -rf *.ko *.mod* *.o* *.sy*
endif

   理解:

      pwd-->  驱动文件目录

      kerneldir -->  内核源码目录

      default : 表示到内核源码目录中去编译pwd下的驱动文件

          make 编译

root@ubuntu:/home/arm/data/char_driver# make
make -C /usr/src/linux-headers-4.4.0-31-generic M=/home/arm/data/char_driver modules
make[1]: 正在进入目录 `/usr/src/linux-headers-4.4.0-31-generic'
  CC [M]  /home/arm/data/char_driver/GlobalCharDev.o
  Building modules, stage 2.
  MODPOST 1 modules
  LD [M]  /home/arm/data/char_driver/GlobalCharDev.ko
make[1]:正在离开目录 `/usr/src/linux-headers-4.4.0-31-generic'

 

出现Global CharDev.ko文件

2,insmod Global CharDev.ko  将模块加入内核

3,cat  /proc/devices  查看驱动设备

 tiny4412--linux驱动学习(2) 随笔

 

 4,mknod  /dev/GlobalChar   c  247  0      根据相应的设备号,建立设备节点。

5,测试文件

/* GlobaiCharText.c 测试文件*/

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

#define DEV_NAME "/dev/GlobalChar"

int main()
{
     int fd, num;

     /* 打开设备文件 */
     fd = open(DEV_NAME, O_RDWR, S_IRUSR | S_IWUSR);
     if(fd < 0)
     {
     printf("Open Device Fail!\n");
          return -1;
     }

     /* 读取当前设备数值 */
     read(fd, &num, sizeof(int));
     printf("The GlobalChar is %d\n", num);

     printf("Please input a numble written to GlobalChar: ");
     scanf("%d", &num);

     /* 写入新的数值 */
     write(fd, &num, sizeof(int));

     /* 重新读取数值 */
     read(fd, &num, sizeof(int));
     printf("The GlobalChar is %d\n", num);

     close(fd);
     return 0;

}

 

   gcc -o  GlobalCharText  GlobalCharText.c      编译出可执行文件

   执行:

root@ubuntu:/home/arm/data/char_driver# ./a.out 
The GlobalChar is 0
Please input a numble written to GlobalChar: 111
The GlobalChar is 111

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄