驱动笔记 - ioctl

#include <linux/ioctl.h>

定义命令
_IO(type,nr) 没有参数的命令
_IOR(type,nr,datatype) 从驱动中读数据
_IOW(type,nr,datatype) 写数据到驱动
_IOWR(type,nr,datatype) 双向传送,type和number成员作为参数被传递
例:
#define MEM_IOC_MAGIC 'm'
#define MEM_IOCSET _IOW(MEM_IOC_MAGIC,0,int)
#define MEM_IOCGQSET _IOR(MEM_IOC_MAGIC,1,int)

unlock_ioctl一般使用switch,不匹配的命令通常返回-EINVAl

应用层调用ioctl

#include <linux/ioctl.h>
ioctl(int fd,int command, (char*)argstruct)

参数检测(检测是否有效)
int access_ok(int type, const void *addr, unsigned long size)
一般把addr强制转化为(void __user *)
type:VERIFY_READ或者VERIFY_WRITE
size:操作的大小
返回值:1成功 0失败
access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd))
access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));

不需要检测(函数中自带有检测)
unsigned long copy_from_user (void * to, const void __user * from, unsigned long n) //此函数自带access_ok
unsigned long copy_to_user (void __user * to, const void * from, unsigned long n) //此函数自带access_ok
get_user
put_user

需要检测
__get_user
__get_user(tmp, (int __user *)arg);

__put_user

例:

long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int err = 0,tmp;
int retval = 0; if(_IOC_TYPE(cmd) != MEMDEV_MAGIC)
return -ENOTTY;
if(_IOC_NR(cmd) > MEMDEV_MAXNR)
return -ENOTTY;
if(_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
else if(_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
if(err)
return -EFAULT; switch(cmd)
{
case MEMDEV_TELL:
printk(KERN_ALERT "Your call MEMDEV_TELL.\n");
break;
case MEMDEV_RECEIVE:
if(retval = __get_user(tmp, (int __user *)arg) == 0)
{
printk(KERN_ALERT "memdev receive number is %d\n",tmp);
}
else
printk(KERN_ALERT "No receive.\n");
break;
case MEMDEV_SET:
tmp = 110;
if(retval = __put_user(tmp, (int __user *)arg) == 0)
{
printk(KERN_ALERT "memdev send number is %d\n", tmp); }
else
printk(KERN_ALERT "Sent error\n");
break;
default:
return -ENOTTY;
}
return retval;
}

  

上一篇:命名空间 - PHP手册笔记


下一篇:SIP SDP Profile-level-id解析