通常用户空间和内核空间的交互利用read和write即可实现,部分特殊情况下可利用ioctl更加便捷。以下为驱动添加ioctl函数定义,处理用户空间传递来的各种指令并交互结构体。(其中函数第三个参数arg默认为unsigned long类型四字节,但大部分情况传递的都是地址,该四字节存的本身就是地址,因此使用copy***user函数的时候无需对其加&取地址符)
结合上一篇linux驱动开发简单示例,在zhancghen_test.c中添加如下代码:
//新增传输的数据结构体
typedef struct
{
int iNum;
char aData[128];
}tTransferBuf;
//新增魔术和指令宏定义
#define ZHANGCHEN_TEST_MAGIC 'a'
#define ZHANGCHEN_TEST_CMD_SET_VAL _IOW(ZHANGCHEN_TEST_MAGIC, 1, tTransferBuf)
#define ZHANGCHEN_TEST_CMD_GET_VAL _IOR(ZHANGCHEN_TEST_MAGIC, 2, tTransferBuf)
static tTransferBuf g_s_buffer;
//增加ioctl函数映射
static struct file_operations g_test_fops = {
...
...
.unlocked_ioctl = zhangchen_test_ioctl,
};
//驱动内ioctl定义,利用switch处理各种指令
static long zhangchen_test_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
int ret = 0;
if (_IOC_TYPE(cmd) != ZHANGCHEN_TEST_MAGIC) {
pr_err("%s: command type [%c] error.\n", __func__, _IOC_TYPE(cmd));
return -ENOTTY;
}
switch(cmd) {
case ZHANGCHEN_TEST_CMD_SET_VAL:
printk("Transfer arg[%lu]\n" , arg);
if(copy_from_user(&g_s_buffer , (tTransferBuf *)arg , sizeof(tTransferBuf)))
{
printk(KERN_ALERT "Func copy_from_user failed!\n");
return -EFAULT;
}
printk("Func ioctl set id[%d] data[%s]\n" , g_s_buffer.iNum , g_s_buffer.aData);
ret = 1;
break;
case ZHANGCHEN_TEST_CMD_GET_VAL:
if(copy_to_user((tTransferBuf *)arg , &g_s_buffer , sizeof(tTransferBuf)))
{
printk(KERN_ALERT "Func copy_to_user failed!\n");
return -EFAULT;
}
printk("Func ioctl get id[%d] data[%s]\n" , g_s_buffer.iNum , g_s_buffer.aData);
ret = 2;
break;
default:
pr_err("%s: invalid command.\n", __func__);
ret = -ENOTTY;
break;
}
return ret;
}
测试代码test.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
typedef struct
{
int iNum;
char aData[128];
}tTransferBuf;
#define ZHANGCHEN_TEST_MAGIC 'a'
#define ZHANGCHEN_TEST_CMD_SET_VAL _IOW(ZHANGCHEN_TEST_MAGIC, 1, tTransferBuf)
#define ZHANGCHEN_TEST_CMD_GET_VAL _IOR(ZHANGCHEN_TEST_MAGIC, 2, tTransferBuf)
int main(int argc,char **argv)
{
int fd;
tTransferBuf stTmp;
fd = open("/dev/zhangchen_dev",O_RDWR);
if(-1==fd)
{
printf("Func open failed!\n");
return -1;
}
memset(&stTmp , 0 , sizeof(stTmp));
stTmp.iNum = 666;
strcpy(stTmp.aData , "zzzz");
if(ioctl(fd , ZHANGCHEN_TEST_CMD_SET_VAL , &stTmp) < 0)
{
printf("Func ioctl failed!\n");
return -2;
}
printf("Ioctl set id[%d] data[%s]\n" , stTmp.iNum , stTmp.aData);
memset(&stTmp , 0 , sizeof(stTmp));
if(ioctl(fd , ZHANGCHEN_TEST_CMD_GET_VAL, &stTmp) < 0)
{
printf("Func ioctl failed!\n");
return -2;
}
printf("Ioctl get id[%d] data[%s]\n" , stTmp.iNum , stTmp.aData);
close(fd);
puts("Exit");
return 0;
}