ons 发生了重大的在 2.6.36 内核上 file_operati改变 :
原先的, 参见include/linux/fs.h, version 2.6.17, line 1015
int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long); //在应用层调用会传入驱动中
原文链接:https://blog.csdn.net/gatieme/article/details/71437163
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
ioctl的cmd命令函数定义在ioctl.h,位于、include\uapi\asm-generic\ioctl.h
static long timer_ioctl(struct file *file, unsigned int cmd,
unsigned long arg) //第一个是文件,第二个是命令,第三个是参数
{ }
/*字符设备操作集*/
static const struct file_operations timer_fops = {
.owner = THIS_MODULE,
.open = timer_open,
.release = timer_release,
//.write = timer_write, 这里用的是unlocked_ioctl
.unlocked_ioctl = timer_ioctl,
};
type是幻术,nr是序数,size是大小,用于下面这些api
/* used to create numbers */编码
#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)//没有参数的命令
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size))) //从驱动读取数据
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) //向驱动写入数据
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) //双向数据传输
#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
/* used to decode ioctl numbers.. */ 用于解码
#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
在驱动层copy_from_user()从应用层获取参数到驱动层
copy_from_user(void *to, const void __user *from, unsigned long n)
第一个是传到那里,第二个是从那里,第三个是传入类型大小sizeof();
用户层
/*循环读取*/
while(1){
printf("Input CMD:");
ret = scanf("%d", &cmd);//返回输入个数
if(ret != 1){
//从标准输入(通常是键盘)读取一行文本(包括空格)并存入字符数组的函数/*防止卡死*/
fgets(str, sizeof(str), stdin);
}
if(cmd==1){ /*关闭*/
ioctl(fd, CLOSE_CMD, &arg);//这个函数会传入驱动中
}else if(cmd==2){ /*打开*/
ioctl(fd, OPEN_CMD, &arg);;
}else if(cmd==3){ /*修改周期*/
printf("Input Timer period:");
ret = scanf("%d", &arg);//输入修改的周期参数
if(ret != 1){
fgets(str, sizeof(str), stdin);/*防止卡死*/
}
ioctl(fd, PERIOD_CMD, &arg);//把参数和命令传入驱动
}
}
在驱动层响应ioctl(fd, xxxxx_CMD, &arg);传入编写的下列函数中
static long timer_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret = 0;
int value;
struct timer_dev *dev = file->private_data; //获取私有数据
switch (cmd)
{
case CLOSE_CMD:
del_timer_sync(&dev->timer); //删除定时器
break;
case OPEN_CMD:
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->timerperiod)); //打开定时器
break;
case PERIOD_CMD:
ret = copy_from_user(&value, (int *)arg, sizeof(int));//因为arg形式参数,这里需要地址指向用户传入的参数的地址
if(ret){
return -EFAULT;
}
dev->timerperiod = value;
mod_timer(&dev->timer,jiffies+msecs_to_jiffies(dev->timerperiod));
break;
}
return ret;
}