zheguzai 发表于 2012-05-04 17:30

应用程序通过iotcl往驱动传参数,居然收到是错的。。。。。

本帖最后由 zheguzai 于 2012-05-04 17:46 编辑

今天遇到这个问题,简直让我很吐血,搞了好久还是不行,因为感觉这个根本就不会出问题的,可是居然出了这种问题
以前的驱动要添加接口,所以我就在原来驱动的ioctl中添加了一项,并且通过应用程序调用该ioctl,可是奇怪的事情发生了,我传递给
驱动的数据,居然不是我想要的,搞了半天都不行,期间试了两种方法,第一种:驱动中不用copy_from_user()函数来接收从应用传来的指针,可是这样也不行,第二种,就是用copy_from_user()函数来接受从应用传来的指针,可是还是不行。不说了上代码,大家帮我看看,哪里出问题了。。。。

应用层代码,调用的代码很简单就两句。。。。我从应用传过去的数据就是1和2,其他的数据都会报错的。
      int channel= 2;
        if (ioctl(inputFd, VPFE_CMD_SELECT_TVP5158_CHANNEL, &channel) == -1)
                        {
                                printf("VPFE_CMD_SELECT_TVP5158_CHANNEL failed\n");
                        }驱动代码: case VPFE_CMD_SELECT_TVP5158_CHANNEL:
      {   
   
            intchannel_id;

            copy_from_user(&channel_id, (int *)arg, sizeof(int));
         
            printk("channel_id = %d\n",channel_id);//本来这句打印出来应该是2的,可是它不是,是个垃圾数值,

            if (channel_id < 1 || channel_id > 2)
            {   
                ret = -EINVAL;
                break;
            }   

            tvp5158_ctrl(TVP5158_SELECT_CHANNEL, &channel_id);
            break;
      }   

驱动中刚开始用这种方式实现的。一样是不行的 case VPFE_CMD_SELECT_TVP5158_CHANNEL:
      {   
   
            int*channel_id = (int *)arg;
         
            printk("channel_id = %d\n",*channel_id);//本来这句打印出来应该是2的,可是它不是,是个垃圾数值,

            if (*channel_id < 1 || *channel_id > 2)
            {   
                ret = -EINVAL;
                break;
            }   

            tvp5158_ctrl(TVP5158_SELECT_CHANNEL, channel_id);
            break;
      }    大家帮我看看,看是哪里出错了,谢谢了 。。。。。。。。。。

xxw19840406 发表于 2012-05-04 18:03

本帖最后由 xxw19840406 于 2012-05-04 18:04 编辑

void __user *arg = (void __user *)arg;
驱动中arg有没有这个

然后copy_from_user(&channel_id, (int *)arg, sizeof(int));
改成 copy_from_user(&channel_id, arg, sizeof(int));

代码贴全点

zheguzai 发表于 2012-05-04 19:35

xxw19840406 发表于 2012-05-04 18:03 static/image/common/back.gif
void __user *arg = (void __user *)arg;
驱动中arg有没有这个




驱动里面没有你说的void __user *arg = (void __user *)arg; 这句的。

yyplc 发表于 2012-05-04 20:58

不应该用copy_from_user的:wink:

xxw19840406 发表于 2012-05-07 09:40

zheguzai 发表于 2012-05-04 19:35 static/image/common/back.gif
驱动里面没有你说的void __user *arg = (void __user *)arg; 这句的。
这个不一定是真正的原因
一般copy_from_user都是要检查返回的,LZ可以看看是否出错

zheguzai 发表于 2012-05-07 10:09

xxw19840406 发表于 2012-05-07 09:40 static/image/common/back.gif
这个不一定是真正的原因
一般copy_from_user都是要检查返回的,LZ可以看看是否出错



查过了,返回值就是错误的。。。。

yxchugo 发表于 2012-05-12 10:40

ldd3 中的做法是:因为ioctl 通常涉及到小的数据,所以先用access_ok()验证用户空间地址有效性,
然后使用不做类型检查的快速的函数:put_user(), __put_user(), get_user,__get_user().

你把代码改成这样试试。 case VPFE_CMD_SELECT_TVP5158_CHANNEL:
      {   
   
            intchannel_id;

            int err = access_ok(VERIFY_READ, (void __user*)arg, _IOC_SIZE(cmd));
            if(!err)    return -EFAULT;
            __get_user(channel_id, (int __user *)arg);
         
            printk("channel_id = %d\n",channel_id);//本来这句打印出来应该是2的,可是它不是,是个垃圾数值,

            if (channel_id < 1 || channel_id > 2)
            {   
                ret = -EINVAL;
                break;
            }   

            tvp5158_ctrl(TVP5158_SELECT_CHANNEL, &channel_id);
            break;
      }   

azzurris 发表于 2012-05-23 14:19

友情提醒:你检查一下你的ioctl的原型和你的ioctl函数的实现,看看两者的参数个数是不是一致。

shaneqi 发表于 2012-05-23 21:07

做个记号,下次好找!

zheguzai 发表于 2012-06-05 16:12

非常感谢大家的回帖,那个davinci VPFE驱动里对IOCTL又进行了一次封装,本来我们只写一个ioctl函数的,它又写了一个调用真正的ioctl,并且对参数进行了处理。。。所以我的那个参数传进去之后就不对了。。。
页: [1]
查看完整版本: 应用程序通过iotcl往驱动传参数,居然收到是错的。。。。。