通过IOCTL将struct传递给设备驱动程序

时间:2012-08-26 13:55:23

标签: linux linux-kernel linux-device-driver ioctl

我正在尝试将结构从用户空间传递到内核空间。我已经尝试了很多个小时但它不起作用。这是我到目前为止所做的......

int device_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg){

int ret, SIZE;


switch(cmd){

    case PASS_STRUCT_ARRAY_SIZE:

        SIZE = (int *)arg;
        if(ret < 0){
            printk("Error in PASS_STRUCT_ARRAY_SIZE\n");
            return -1;  
        }
        printk("Struct Array Size : %d\n",SIZE);
        break;

    case PASS_STRUCT:


        struct mesg{
            int pIDs[SIZE];
            int niceVal;
        };

        struct mesg data;

        ret = copy_from_user(&data, arg, sizeof(*data));
        if(ret < 0){
            printk("PASS_STRUCT\n");
            return -1;  
        }

        printk("Message PASS_STRUCT : %d\n",data.niceVal);
        break;

    default :
        return -ENOTTY;
}

return 0;
  }

我无法定义结构。定义它的正确方法是什么?我想要int pIDs [SIZE]。 int * pID会这样做(在用户空间中它被定义为pIDs [SIZE])吗?

编辑:

通过上述更改,我收到此错误?错误:在&#39; struct&#39;之前的预期表达式任何想法?

1 个答案:

答案 0 :(得分:1)

您的问题中有两种结构变体。

 struct mesg1{
  int *pIDs;
  int niceVal;
 };

 struct mesg2{
  int pIDs[SIZE];
  int niceVal;
 };

他们是不同的;在mesg1的情况下,你有指向int数组的指针(在结构之外)。在其他情况下(mesg2),struct中有int数组。

如果您的SIZE已修复(在模块的API中;用户和内核空间中使用的值相同),则可以使用第二个变体(mesg2)。

要使用结构的第一个变体(mesg1),您可以将字段size添加到结构本身,例如:

 struct mesg1{
  int pIDs_size;
  int *pIDs;
  int niceVal;
 };

并用*pIDs指向的整数计数填充它。

PS:并且,从不在结构中间使用具有可变大小数组的结构(也称为VLAIS)。这是GCC编译器对C语言的专有,奇怪,错误和non-documented扩展。根据国际C标准,只有结构的最后一个字段可以是array with variable size(VLA)。这里有一些示例:1 2

PPS:

您可以使用VLA声明结构(如果只有一个具有可变大小的单个数组):

 struct mesg2{
  int niceVal;
  int pIDs[];
 };

但是在使用VLA

为这样的结构分配内存时应该小心