学做网站需要多久时间,asp做网站,最好的网站建设公司排名,做网站常用什么软件若该文为原创文章#xff0c;转载请注明原文出处 本文章博客地址#xff1a;https://hpzwl.blog.csdn.net/article/details/135384355
红胖子网络科技博文大全#xff1a;开发技术集合#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…若该文为原创文章转载请注明原文出处 本文章博客地址https://hpzwl.blog.csdn.net/article/details/135384355
红胖子网络科技博文大全开发技术集合包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等持续更新中…
Linux系统移植和驱动开发专栏
上一篇《Linux驱动开发笔记五驱动连接用户层与内核层的文件操作集原理和Demo》 下一篇敬请期待… 前言 驱动作为桥梁用户层调用预定义名称的系统函数与系统内核交互而用户层与系统层不能直接进行数据传递进行本篇主要就是理解清楚驱动如何让用户编程来实现与内核的数据交互传递。 温故知新
设备节点是应用层用户层与内核层交互使用预先的结构体进行操作如系统open函数对应了驱动中文件操作及的open指针结构体struct file_operations文件操作集结构体填充结构体对应指针填充自己使用到的就行了多余的可以不填充调用也不会崩溃或返回错误会返回0 那么如何将应用层的输入写入进去可用如何将内核层的数据通过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需要使用内核库printkprintk(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。 在内核中可以使用printkmemsetmemcpystrlen等函数。 内核函数 头文件是linux/uaccess.h我们这是ubuntu不是arm 可以在内核根目录下搜索下
find . -type f -exec grep -l copy_to_user(void {} \;copy_from_user函数从用户层复制到内核层
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)参数分别是复制到的地址内核空间从什么地址复制用户空间复制长度
copy_to_user函数从内核层复制到用户层
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)参数分别是复制到的地址用户空间从什么地址复制内核空间复制长度 杂项设备驱动添加数据传递函数Demo
步骤一加入头文件和定义static缓存区 #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;
}步骤三在驱动函数read中添加从内核层到用户层的函数 // 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;
}步骤四在驱动函数wirte中添加从用户层到内核层的函数 // 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.hint 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