3.用户程序与驱动交互

news/2024/7/8 7:45:51 标签: linux

驱动程序请使用第二章https://blog.csdn.net/chenhequanlalala/article/details/140034424

用户app与驱动交互最常见的做法是insmod驱动后,生成一个设备节点,app通过open,read等系统调用去操作这个设备节点,这里先用mknode命令调试。

mknod 设备名 设备类型(b块设备/c字符设备/p管道) 主设备号 次设备号

mknod /dev/hello c 240 0

 使用mknode后生成了/dev/hello节点,写入数据到hello节点中,查看dmesg的输出发现调用了驱动的open write release

echo 1 > /dev/hello

[  802.771723] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_open 48
[  802.773196] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_write 40
[  802.773285] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_release 56
 

 这里写一个C程序来读写这个设备节点

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

/*
读数据 ./hello_test xxx(设备节点名字)
写数据 ./hello_test xxx(设备节点名字) string
*/

int main(int argc, char **argv)
{
    int fd;
    int len;
    char buf[1024];

    if(argc < 2)
    {
        printf("Usage :\n");
        printf("%s <dev> [str]\n", argv[0]);
        return -1;
    }

    //open
    fd = open(argv[1], O_RDWR);
    if(fd < 0)
    {
        printf("open %s failed\n", argv[1]);
        return -1;
    }

    //read
    if(argc == 2)
    {
        len = read(fd, buf, sizeof(buf));
        printf("%s\n", buf);
    }
    //write
    else if(argc == 3)
    {
        len = write(fd, argv[2], strlen(argv[2]));
    }
    else
    {
        printf("Too many parameters\n");
    }

    close(fd);
}

分别调用 ./hello_test /dev/hello 123 和 ./hello_test /dev/hello 后,查看dmesg输出显示

[ 2770.434595] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_open 48
[ 2770.434664] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_write 40
[ 2770.434705] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_release 56
[ 2772.388372] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_open 48
[ 2772.388439] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_read 32
[ 2772.389257] /home/book/nfs_rootfs/drivers_projects/01_hello_drv/hello_drv.c hello_release 56

 app的open write read release都一一对应上了。

这里的./hello_test /dev/hello其实没有读到数据,因为驱动程序中并没有和app交互数据。

[root@100ask:/mnt/drivers_projects/01_hello_drv]# ./hello_test /dev/hello
read size = 1024 data = 
 

 app与驱动交换数据通过copy_from_user和copy_to_user来实现

copy_to_user(void __user *to, const void *from, unsigned long n);
copy_from_user(void *to, const void __user *from, unsigned long n);

在驱动程序中添加一个buf用来保存用户的数据,用copy_from_user保存数据,用copy_to_user读取数据。

#include "asm/uaccess.h"
#include "linux/scatterlist.h"
#include "linux/types.h"
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/raw.h>
#include <linux/tty.h>
#include <linux/capability.h>
#include <linux/ptrace.h>
#include <linux/device.h>
#include <linux/highmem.h>
#include <linux/backing-dev.h>
#include <linux/shmem_fs.h>
#include <linux/splice.h>
#include <linux/pfn.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/uio.h>
#include <linux/module.h>

#include <linux/uaccess.h>

#define DEVICE_NAME "hello_device"
static int major;
#define hello_buf_size 100
static unsigned char hello_buf[hello_buf_size];

//ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
//参数含义依次为 要读取的文件指针 用户保存数据的buf 读取数据大小 文件内容的偏移量
static ssize_t hello_read (struct file * filp, char __user *buf, size_t size, loff_t *offset)
{
    unsigned long len = size > hello_buf_size ? hello_buf_size : size;
    copy_to_user(buf, hello_buf, len);
	printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	return len;
}

//ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
//参数含义依次为 要写入的文件指针 用户要写入的数据buf 写入数据大小 文件内容的偏移量
static ssize_t hello_write (struct file *filp, const char __user *buf, size_t size, loff_t *offset)
{
    unsigned long len = size > hello_buf_size ? hello_buf_size : size;
    copy_from_user(hello_buf, buf, len);
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    return len;
}

//int (*open) (struct inode *, struct file *);
//参数含义依次为 文件索引节点 文件指针
static int hello_open (struct inode *node, struct file *filp)
{
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    return 0;
}

//int (*release) (struct inode *, struct file *);
//参数含义依次为 文件索引节点 文件指针
static int hello_release (struct inode *node, struct file *filp)
{
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    return 0; 
}

/*构建file_operations结构体*/
static const struct file_operations hello_fops = {
    .owner      = THIS_MODULE,
	.read		= hello_read,
	.write		= hello_write,
	.open		= hello_open,
    .release    = hello_release,
};

/*init函数,实现register_chrdev*/
static int __init hello_init(void)
{
    //数含义依次为 主设备号,如果为0,内核会自动分配一个可用的。设备名,会在/proc/devices中显示。 file_operations结构体
    //注册成功就返回主设备号
    major = register_chrdev(0, DEVICE_NAME, &hello_fops);
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    return 0;
}

/*exit函数unregister_chrdev*/
static void __exit hello_exit(void)
{
    //数含义依次为 主设备号 设备名
    unregister_chrdev(major, DEVICE_NAME);
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}

module_init(hello_init);
module_exit(hello_exit);
//遵循GPL协议
MODULE_LICENSE("GPL");

重新insmod驱动后,执行测试程序

[root@100ask:/mnt/drivers_projects/01_hello_drv]# ./hello_test /dev/hello 123456
[root@100ask:/mnt/drivers_projects/01_hello_drv]# ./hello_test /dev/hello       
read size = 100 data = 123456
[root@100ask:/mnt/drivers_projects/01_hello_drv]# ./hello_test /dev/hello hello
[root@100ask:/mnt/drivers_projects/01_hello_drv]# ./hello_test /dev/hello 
read size = 100 data = hello6
 

 这里第二次输出hello6,是因为copy_from_user只是写入指定长度的数据,第一次写入的123456只覆盖了前5字节。


http://www.niftyadmin.cn/n/5536857.html

相关文章

arm_uart4实验

#include "uart4.h" //UART //初始化 void hal_uart4_init() { //rcc_init //…

C#的多线程UI窗体控件显示方案

在C#中&#xff0c;特别是在使用Windows窗体&#xff08;WinForms&#xff09;或WPF&#xff08;Windows Presentation Foundation&#xff09;进行UI开发时&#xff0c;处理多线程与UI控件的交互需要特别小心。由于UI控件不是线程安全的&#xff0c;直接从非UI线程&#xff08…

VS Code解释及快捷键

一、VS Code Visual Studio Code&#xff08;简称 VS Code&#xff09;是由微软开发的一款免费、开源的代码编辑器。它具有丰富的功能和扩展性&#xff0c;广泛应用于各种编程语言的开发环境。以下是对 VS Code 的详细介绍&#xff1a; 主要特性 1. 跨平台 VS Code 支持 Wi…

人员定位系统方案的定制,主要明确的系统功能有哪几部分?

人员定位系统对于安全监管和工作效率有很大的帮助&#xff0c;现在&#xff0c;不同领域也开始定制了专门的人员定位系统方案&#xff0c;那么&#xff0c;这一系统在定制之前&#xff0c;需要明确的系统功能主要包含了哪些部分呢? 一、首先是人员的精确定位功能 需要做到精…

java解析请求的字符串参数Content-Disposition: form-data;和拼接的键值对

项目场景&#xff1a; 获取到http请求的参数&#xff0c;已经被字符串接收了&#xff0c;需求是需要从字符串中解析出来。 一种情况是&#xff1a;Content-Disposition: form-data; name"userCode" 另一种是&#xff1a;key1value1&key2value2&key3value3…

微信小程序留言板1

wxml&#xff1a; <view class"view2"> <text class"test1">留言&#xff1a;</text><input type"text" class"input1" bindinput"ipt"/><button class"btn" bindtap"btn"…

【云原生】服务网格(Istio)如何简化微服务通信

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《未来已来&#xff1a;云原生之旅》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、微服务架构的兴起 2、Istio&#xff1a;服务网格的佼…

上海-灵曼科技(面经)

上海-灵曼科技 hr电话面 个人简介 个人信息的询问 是否知道芋道框架 技术面 算法题 14. 最长公共前缀&#xff08;写出来即可&#xff09; 聊一下Docker Docker核心概念总结Docker实战 聊一下AOP Spring AOP详解 聊一下JWT JWT 基础概念详解JWT 身份认证优缺点分析 Spri…