zoukankan      html  css  js  c++  java
  • 13、字符设备驱动的使用

    编译和安装驱动

    下面是通过一个例子来学会使用驱动程序:

    1---驱动程序:

    Memdev.c

    #include <linux/module.h>

    #include <linux/fs.h>

    #include <linux/init.h>

    #include <linux/cdev.h>

    #include <asm/uaccess.h>

    int dev1_registers[5];

    int dev2_registers[5];

    struct cdev cdev;

    dev_t devno;

    /*文件打开函数*/

    int mem_open(struct inode *inode, struct file *filp)

    {

    /*获取次设备号*/

    int num = MINOR(inode->i_rdev);

    if (num==0)

    filp->private_data = dev1_registers;

    else if(num == 1)

    filp->private_data = dev2_registers;

    else

    return -ENODEV; //无效的次设备号

    return 0;

    }

    /*文件释放函数*/

    int mem_release(struct inode *inode, struct file *filp)

    {

    return 0;

    }

    /*读函数*/

    static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)

    {

    unsigned long p = *ppos;

    unsigned int count = size;

    int ret = 0;

    int *register_addr = filp->private_data; /*获得设备的寄存器地址*/

    /*判断读位置是否有效*/

    if (p >= 5*sizeof(int))

    return 0;

    if (count > 5*sizeof(int) - p)

    count = 5*sizeof(int) - p;

    /*读取数据到用户空间*/

    if (copy_to_user(buf, register_addr+p, count))

    {

    ret = -EFAULT;

    }

    else

    {

    *ppos += count;

    ret = count;

    }

    return ret;

    }

    /*写函数*/

    static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)

    {

    unsigned long p = *ppos;

    unsigned int count = size;

    int ret = 0;

    int *register_addr = filp->private_data; /*获取设备的寄存器地址*/

    /*分析和获取有效的写长度*/

    if (p >= 5*sizeof(int))

    return 0;

    if (count > 5*sizeof(int) - p)

    count = 5*sizeof(int) - p;

    /*从用户空间写入数据*/

    if (copy_from_user(register_addr + p, buf, count))

    ret = -EFAULT;

    else

    {

    *ppos += count;

    ret = count;

    }

    return ret;

    }

    /* seek文件定位函数*/

    static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)

    {

    loff_t newpos;

    switch(whence) {

    case SEEK_SET:

    newpos = offset;

    break;

    case SEEK_CUR:

    newpos = filp->f_pos + offset;

    break;

    case SEEK_END:

    newpos = 5*sizeof(int)-1 + offset;

    break;

    default:

    return -EINVAL;

    }

    if ((newpos<0) || (newpos>5*sizeof(int)))

        return -EINVAL;

          

    filp->f_pos = newpos;

    return newpos;

    }

    /*文件操作结构体*/

    static const struct file_operations mem_fops =

    {

    .llseek = mem_llseek,

    .read = mem_read,

    .write = mem_write,

    .open = mem_open,

    .release = mem_release,

    };

    /*设备驱动模块加载函数*/

    static int memdev_init(void)

    {

    /*初始化cdev结构*/

    cdev_init(&cdev, &mem_fops);

    /* 注册字符设备*/

    alloc_chrdev_region(&devno, 0, 2, "memdev");

    cdev_add(&cdev, devno, 2);

    }

    /*模块卸载函数*/

    static void memdev_exit(void)

    {

    cdev_del(&cdev); /*注销设备*/

    unregister_chrdev_region(devno, 2); /*释放设备号*/

    }

    MODULE_LICENSE("GPL");

    module_init(memdev_init);

    module_exit(memdev_exit);

    Makefile:

    obj-m := memdev.o

    KDIR:=/home/linux-ok6410/

    all:

        make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm

    clean:

        rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order

    这两个文件写好了之后执行:make的结果:

    执行后生成:memdev.ko:

    这就是我们要的驱动了。

    我们把生成的驱动文件拷贝到我们的开发板:

     

     

     

     

     

     

     

    接下来我们来创建字符设备文件

    我们往系统里面写东西,我们把东西写进字符设备文件,再从设备文件读出。

    创建字符设备文件:

    命令:mknod命令:

    Mknod /dev/文件名 c 主设备号 次设备号

    注释:文件名是自己定义的,只有不要和/dev/下的文件重名即可。C表示的是字符文件。主设备号我们可以用:cat /proc/devices查看。

    我们从上图可以看到主设备号为252,次设备号是随便取的,只要不要是0-256就可以。

    创建:mknod /dev/memdev0 c 252 0

    我们在dev目录下创建的字符设备文件是memdev0。

    接下来就是。我们要写两个应用程序:一个write_mem.c:往字符设备写信息,另一个是read_mem.c:从字符设备里面读出信息。

    Write_mem.c:

    我们可以man read/write一下。看看需要包含的头文件。我们把write_mem.c编译好,放到开发板去运行。很有可能出现:

    ~/bin/sh:./write_mem:not found的错误。

    这是因为我们没有加上-static关键字,缺少动态链接库的缘故。

    Read_mem.c:

    这是从字符设备读取信息的函数。我们同样:arm-linux-gcc -static read_mem.c -o read_mem把生成的文件拷贝到开发板。

    执行的结果下:

    我们开始通过write_mem.c往字符设备文件里面写了信息。接着我们通过read_mem.c把内容读出来。

    运行的简图:

    流程图的简解释:

    Write方法利用字符设备文件,通过字符设备驱动,往模拟的机器(数组)写东西。Read方法利用字符设备文件,通过字符设备驱动,从模拟的机器把信息读取出来。

  • 相关阅读:
    基于redission的分布式锁
    kafka在Windows环境下启动
    Synchronized优化总结
    mysql死锁总结
    索引是建立得越多越好吗?
    show processlist 详解
    RocketMQ高可用机制同步刷盘、异步刷盘和同步复制、异步复制
    Redlock红锁总结
    C#2.0泛型
    《解剖PetShop》系列之四:PetShop之ASP.NET缓存 (转)
  • 原文地址:https://www.cnblogs.com/FORFISH/p/5188450.html
Copyright © 2011-2022 走看看