El controlador de Linux implementa la estructura de transferencia ioctl

Por lo general, la interacción entre el espacio del usuario y el espacio del kernel se puede lograr mediante lectura y escritura. En algunos casos especiales, se puede usar ioctl para hacerlo más conveniente. A continuación se agrega una definición de función ioctl al controlador para procesar varias instrucciones pasadas desde el espacio del usuario e interactuar con estructuras. (El tercer parámetro arg de la función tiene por defecto cuatro bytes de tipo largo sin firmar, pero en la mayoría de los casos se pasa la dirección. Los cuatro bytes almacenados son en sí mismos direcciones, por lo que no es necesario copiarlos cuando se utiliza copy***user función Agregar y tomar caracteres de dirección)

Combinado con el ejemplo simple anterior de desarrollo de controladores de Linux , agregue el siguiente código en 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;
}

Código de prueba 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;
}

Guess you like

Origin blog.csdn.net/jiujiederoushan/article/details/128948762