若该文为原创文章,转载请注明原文出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/135384355
红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…
上一篇:《Linux驱动开发笔记(五):驱动连接用户层与内核层的文件操作集原理和Demo》
下一篇:敬请期待…
??驱动作为桥梁,用户层调用预定义名称的系统函数与系统内核交互,而用户层与系统层不能直接进行数据传递,进行本篇主要就是理解清楚驱动如何让用户编程来实现与内核的数据交互传递。
??那么如何将应用层的输入写入进去可用,如何将内核层的数据通过read返回出来,就是本篇学习了。
??首先复制之前的testFileOpts的驱动,改个名字为:testFileOpts:
cd ~/work/drive/
ls
cp -arf 003_testFileOpts 004_testReadWrite
cd 004_testReadWrite/
make clean
ls
mv testFileOpts.c testReadWrite.c
vi Makefile
ls
??
??其中修改makefile里面的模块名称(obj-m模块名称),模板准备好了
gedit Makefile
??
??下面基于testReadWrite.c文件进行注册杂项设备,修改.c文件:
gedit testReadWrite.c
??
??
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
// int (*open) (struct inode *, struct file *);
int misc_open(struct inode * pInode, struct file * pFile)
{
printk("int misc_open(struct inode * pInode, struct file * pFile)\n");
return 0;
}
// int (*release) (struct inode *, struct file *);
int misc_release(struct inode * pInde, struct file * pFile)
{
printk("int misc_release(struct inode * pInde, struct file * pFile)\n");
return 0;
}
// ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t misc_read(struct file * pFile, char __user * pUser, size_t size, loff_t *pLofft)
{
printk("ssize_t misc_read(struct file * pFile, char __user * pUser, size_t size, loff_t *pLofft)\n");
return 0;
}
// ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t misc_write(struct file * pFile, const char __user * pUser, size_t size, loff_t *pLofft)
{
printk("ssize_t misc_write(struct file * pFile, const char __user * pUser, size_t size, loff_t *pLofft)\n");
return 0;
}
struct file_operations misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
.release = misc_release,
.read = misc_read,
.write = misc_write,
};
struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR, // 这个宏是动态分配次设备号,避免冲突
.name = "register_hongPangZi_testReadWrite", // 设备节点名称
.fops = &misc_fops, // 这个变量记住,自己起的,步骤二使用
};
static int registerMiscDev_init(void)
{
int ret;
// 在内核里面无法使用基础c库printf,需要使用内核库printk
printk("Hello, I’m hongPangZi, registeraMiscDev_init\n");
ret = misc_register(&misc_dev);
if(ret < 0)
{
printk("Failed to misc_register(&misc_dev)\n");
return -1;
}
return 0;
}
static void registerMiscDev_exit(void)
{
misc_deregister(&misc_dev);
printk("bye-bye!!!\n");
}
MODULE_LICENSE("GPL");
module_init(registerMiscDev_init);
module_exit(registerMiscDev_exit);
??内核层和用户层不能中是不能直接与用户数据交互,需要使用内核函数copy_to_user和copy_from_user。
??在内核中可以使用printk,memset,memcpy,strlen等函数。
??头文件是:linux/uaccess.h(我们这是ubuntu,不是arm)
??可以在内核根目录下搜索下:
find . -type f -exec grep -l "copy_to_user(void" {} \;
??
??
static __always_inline unsigned long __must_check
copy_from_user(void *to, const void __user *from, unsigned long n)
??简化下:
static unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
??参数分别是,复制到的地址(内核空间),从什么地址复制(用户空间),复制长度;
static __always_inline unsigned long __must_check
copy_to_user(void __user *to, const void *from, unsigned long n)
??简化下:
static unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
??参数分别是,复制到的地址(用户空间),从什么地址复制(内核空间),复制长度;
??
#include <linux/uaccess.h> // Demo_004 add
static char kBuf[256] = {0x00}; // Demo_004 add
??
// int (*open) (struct inode *, struct file *);
int misc_open(struct inode * pInode, struct file * pFile)
{
printk("int misc_open(struct inode * pInode, struct file * pFile)\n");
memcpy(kBuf, "init kBuf", sizeof("init kBuf"));
printk("kBuf = %s\n", kBuf);
return 0;
}
??
// ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t misc_read(struct file * pFile, char __user * pUser, size_t size, loff_t *pLofft)
{
printk("ssize_t misc_read(struct file * pFile, char __user * pUser, size_t size, loff_t *pLofft)\n");
if(copy_to_user(pUser, kBuf, strlen(kBuf)) != 0)
{
printk("Failed to copy_to_user(pUser, kBuf, strlen(kBuf)\n");
return -1;
}
return 0;
}
??
// ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t misc_write(struct file * pFile, const char __user * pUser, size_t size, loff_t *pLofft)
{
printk("ssize_t misc_write(struct file * pFile, const char __user * pUser, size_t size, loff_t *pLofft)\n");
if(copy_from_user(kBuf, pUser, size) != 0)
{
printk("Failed to copy_from_user(kBuf, pUser, size)\n");
return -1;
}
return 0;
}
??
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
int fd = -1;
char buf[32] = {0};
int ret = -1;
const char devPath[] = "/dev/register_hongPangZi_testReadWrite";
fd = open(devPath, O_RDWR);
if(fd < 0)
{
printf("Failed to open %s\n", devPath);
return -1;
}else{
printf("Succeed to open %s\n", devPath);
}
// 读取
ret = read(fd, buf, sizeof(buf) < 0);
if(ret < 0)
{
printf("Failed to read %s\n", devPath);
close(fd);
return 0;
}else{
printf("Succeed to read [%s]\n", buf);
}
// 修改内容
memset(buf, 0x00, sizeof(buf));
memcpy(buf, "Get you content", strlen("Get you content"));
// 写入
ret = write(fd, buf, sizeof(buf));
if(ret < 0)
{
printf("Failed to write %s\n", devPath);
close(fd);
return 0;
}else{
printf("Succeed to write [%s]\n", buf);
}
// 读取
ret = read(fd, buf, sizeof(buf) < 0);
if(ret < 0)
{
printf("Failed to read %s\n", devPath);
close(fd);
return 0;
}else{
printf("Succeed to read [%s]\n", buf);
}
close(fd);
printf("exit\n");
fd = -1;
return 0;
}
??
make
sudo insmod testReadWrite.ko
gcc test.c
sudo ./a.out
??
??测试结果与预期相同
??
??
??
上一篇:《Linux驱动开发笔记(五):驱动连接用户层与内核层的文件操作集原理和Demo》
下一篇:敬请期待…
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/135384355