文章目录
- 一、添加ioctl控制节点
- 二、修改测试APP
- 2.1 测试APP的代码:
- 2.2 驱动代码:
ioctl是用户空间和内核空间相互交流时候用的比较多的一种手段。
我们也可以在HAL层通过ioctl调到驱动里面。
一、添加ioctl控制节点
先看patch 吧
这是在驱动中添加的ioctl函数,同样的在ioctl里面去添加操作函数集合
二、修改测试APP
直接上源码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
// 我们目前只传递一个参数
static int file_ioctl(unsigned int cmd) {
return 1;
}
#define FILECTL_READ _IOR('c',0,unsigned int) //对文件进行读取的命令
#define FILECTL_WRITE _IOW('c',0,unsigned int) //对文件进行写入的命令
int main(int argc,char **argv)
{
if(argc <2)
{
printf("Usage:%s -w <string>\n",argv[0]);
printf("Usage:%s -r \n",argv[0]);
return -1;
}
int fd;
char buf[1024];
fd = open("/dev/filectl",O_RDWR);
if(fd < 0)
{
printf("can not open /dev/filectl\n");
return -1;
}
printf("open /dev/filectl success \n");
// 屏蔽掉原来的参数
// if(strcmp(argv[1],"-w")==0 && argc==3)
// {
// int err = write(fd, argv[2], strlen(argv[2]));
// if (err < 0 ) {
// printf("write /dev/filectl error \n");
// return -1;
// }
// printf("write /dev/filectl success \n");
// }else
// {
// int err = read(fd,buf,1024);
// if (err < 0 ) {
// printf("read /dev/filectl error \n");
// return -1;
// }
// printf("read /dev/filectl success \n");
// buf[1023] = '\n';
//}
// 添加ioctl的函数
if (strcmp(argv[1] , "ior") == 0 ) { //通过参数比较来获取命令
int rc = ioctl(fd, FILECTL_READ); // 通过ioctl 函数去传递参数
if ( rc < 0 ) {
printf("ioctl read /dev/filectl error \n");
return -1;
}
printf("ioctl read /dev/filectl sucess \n");
} else if ( strcmp(argv[1], "iow") == 0 ) {
int rc = ioctl(fd, FILECTL_WRITE, argv[2]);
if ( rc < 0 ) {
printf("ioctl read /dev/filectl error \n");
return -1;
}
printf("ioctl read /dev/filectl sucess \n");
} else {
printf("please input right argv[1], 'ior' or 'iow'");
printf("It will return error\n");
return -1;
}
printf("APP get data %s\n",buf);
close(fd);
return 0;
}
然后我们加载模块,运行测试app
同样的我们还是会存在问题,就是读写的接口这些是有问题的,和之前的逻辑一样,下一步就是完善这个代码逻辑。
目前我们的框架已经是ok的了
话不多说 直接上代码:
2.1 测试APP的代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#define FILECTL_READ _IOR('c', 0, unsigned int) //对文件进行读取
#define FILECTL_WRITE _IOW('c', 0, unsigned int) //对文件进行写入
int main(int argc,char **argv)
{
int temp = 0;
char buffer[1024]; // 存放内核拷贝的数据
if(argc <2)
{
printf("Usage:%s -w <string>\n",argv[0]);
printf("Usage:%s -r \n",argv[0]);
return -1;
}
int fd;
char buf[1024];
fd = open("/dev/filectl",O_RDWR);
if(fd < 0)
{
printf("can not open /dev/filectl\n");
return -1;
}
printf("open /dev/filectl success \n");
if(strcmp(argv[1],"-w")==0 && argc==3)
{
int err = write(fd, argv[2], strlen(argv[2]));
if (err < 0 ) {
printf("write /dev/filectl error \n");
return -1;
}
printf("write /dev/filectl success \n");
printf("APP set data %s\n",argv[2]);
}else if (strcmp(argv[1],"-r")==0) {
int err = read(fd,buf,1024);
if (err < 0 ) {
printf("read /dev/filectl error \n");
return -1;
}
printf("read /dev/filectl success \n");
printf("APP get data %s\n", buf);
buf[1023] = '\n';
} else if (strcmp(argv[1] , "ior") == 0 ) {
int rc = ioctl(fd, FILECTL_READ, &buffer); // 将内核传递的数据读取出来
if ( rc < 0 ) {
printf("ioctl read /dev/filectl error \n");
return -1;
}
printf("ioctl read /dev/filectl sucess \n");
printf("APP get data %s\n", buffer);
buf[1023] = '\n';
} else if ( strcmp(argv[1], "iow") == 0 ) {
int rc = ioctl(fd, FILECTL_WRITE, argv[2]); // 写入数据
if ( rc < 0 ) {
printf("ioctl write /dev/filectl error \n");
return -1;
}
printf("ioctl read /dev/filectl sucess \n");
printf("APP set data %s\n",argv[2]);
} else {
printf("please input right argv[1], 'ior' or 'iow'");
printf("It will return error\n");
return -1;
}
close(fd);
return 0;
}
2.2 驱动代码:
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/major.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/stat.h>
#include <linux/tty.h>
static int major = 0; //确定主设备号,0默认系统分配
static struct class *filectl_class;
unsigned char kbuffer[1024]; // 内核空间的buffer
unsigned char ubuffer[1024]; // 申请一段空间用于存放用户数据
/*
* FILECTL_READ 是和测试传递的参数是一样的才能匹配上
* FILECTL_WRITE 同样如此
*/
#define FILECTL_READ _IOR('c', 0, unsigned int) //对文件进行读取
#define FILECTL_WRITE _IOW('c', 0, unsigned int) //对文件进行写入
static long filectl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret;
printk("[%s %d]1111\n", __FUNCTION__, __LINE__);
switch(cmd) {
case FILECTL_READ:
ret = copy_to_user((void __user *)arg, ubuffer, sizeof(ubuffer)); // 将内核空间的buffer拷贝至用户空间
if(ret < 0) {
printk("[%s %d]copy_to_user error\n ",__FUNCTION__, __LINE__);
}
printk("[%s %s %d]\n", __FILE__, __func__, __LINE__);
break;
case FILECTL_WRITE:
ret = copy_from_user(ubuffer, (void __user *)arg, sizeof(ubuffer));
if(ret < 0) {
printk("[%s %d]copy_from_user error \n ",__FUNCTION__, __LINE__);
}
printk("[%s %s %d]\n", __FILE__, __func__, __LINE__);
break;
}
return 0;
}
ssize_t filectl_read(struct file *file, char __user *buf, size_t size, loff_t *pops)
{
int ret;
printk("[%s %d]\n", __FUNCTION__, __LINE__);
ret = copy_to_user(buf, kbuffer, size);
if(ret < 0) {
printk("[%s %d]copy_to_user error \n ",__FUNCTION__, __LINE__ );
}
printk("[%s %s %d]\n", __FILE__, __func__, __LINE__);
return size;
}
ssize_t filectl_write(struct file *file,const char __user *buf, size_t size, loff_t *pops)
{
int ret;
printk("[%s %d]\n", __FUNCTION__, __LINE__);
ret = copy_from_user(kbuffer, buf, size);
if(ret < 0) {
printk("[%s %d]copy_from_user error \n ",__FUNCTION__, __LINE__ );
}
return size;
}
int filectl_open(struct inode *inode, struct file *file)
{
printk("[%s %d]\n", __FUNCTION__, __LINE__);
return 0;
}
int filectl_close(struct inode *inode, struct file *file)
{
printk("[%s %d]\n", __FUNCTION__, __LINE__);
return 0;
}
// 定义自己的驱动的 file_operations
static struct file_operations filectl_ops = {
.owner = THIS_MODULE,
.read = filectl_read,
.write = filectl_write,
.open = filectl_open,
.release = filectl_close, // 好像没有close这个函数
.unlocked_ioctl = filectl_ioctl, //添加ioclt操作函数
};
static int __init filectl_init(void)
{
// 在初始化的时候进行驱动注册, 设备号, 设备名,核心操作函数
major = register_chrdev(0,"filectl",&filectl_ops);
if(major < 0) {
printk("[%s %d] filectl error\n", __FUNCTION__, __LINE__); // 注册失败
return -1;
}
filectl_class = class_create(THIS_MODULE, "filectl"); // class_create 动态创建dev的类
// IS_ERR 查看指针是否有错误
if(IS_ERR(filectl_class)) {
printk("[%s %d] class_create error\n", __FUNCTION__, __LINE__);
unregister_chrdev(major,"filectl");
return -1;
}
// 创建字符设备
device_create(filectl_class, NULL, MKDEV(major, 0),NULL, "filectl");
printk("[%s %d] filectl driver create success\n", __FUNCTION__, __LINE__);
return 0;
}
static void __exit filectl_exit(void) {
device_destroy(filectl_class, MKDEV(major, 0));
class_destroy(filectl_class);
// 注销字符设备
unregister_chrdev(major,"filectl");
printk("[%s %d]goodbye filectl driver\n", __FUNCTION__, __LINE__);
}
module_init(filectl_init);
module_exit(filectl_exit);
MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("cong.luo");
MODULE_DESCRIPTION ("First file contrl module");
测试结果:
内核使用两个buf,使用 ioctl 和 之前的读写接口互不影响。