通常使用者空間和核心空間的互動利用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;
}