I am writing a simple driver.
Here I'm learning ioctl
calls, they work perfect in copy_to_user
and copy_from_user
part but not in get_user
and put_user
part. It works if I send some data by those functions; problem is when I have to just pass an integer or character value:
long ioctl_funcs(struct file *filp,unsigned int cmd, unsigned long arg)
{
int ret=0;
int len=10;
char val='d';
char valplusone='d';
switch(cmd) {
case IOCTL_HELLO:
printk(KERN_INFO "Hello ioctl world");
case READ_IOCTL:
copy_to_user((char *)arg, buf, 200);
//works fine
break;
case WRITE_IOCTL:
copy_from_user(buf, (char *)arg, len);
//works fine
buf[6]=' ';
buf[7]='t';
buf[8]='o';
buf[9]='o';
buf[10]='\n';
break;
case READ_ONE:
printk(KERN_ALERT "valplusone (put user)is %c \n",valplusone);
put_user(valplusone,(char __user *) arg);
//problem
break;
case WRITE_ONE:
if(access_ok(VERIFY_WRITE,(void*)arg,sizeof(char))!=1)
{
printk(KERN_ALERT "access not ok\n");
return -EFAULT;
}
else{
printk(KERN_ALERT "****arg %l",arg);
get_user(val,(char __user *)arg);
valplusone='t';
printk(KERN_ALERT "val (get user)is %c\n",val);
break;
}
}
return ret;
}
in above part it works fine for the copy to user copy from user but not in case of get_user put_user now the user side code is:
char sent,received;
if(retval=ioctl(fd, WRITE_ONE, sent) < 0)
perror("third ioctl");
printf("you sent %c\nretval is %d\n",sent,retval);
if(ioctl(fd, READ_ONE, received) < 0)
perror("fourth ioctl");
printf("you got %c",received);
-----------------------------------
You must pass addresses, not values. Example:
if (ioctl(fd, READ_ONE, &received) < 0)
…