天天看點

linux驅動實作ioctl傳遞結構體

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