ioctl 和unlock_ioctl函数讨论

本文探讨了在Linux内核2.6.36及以后版本中,从struct file_operations中的ioctl函数指针转变为unlocked_ioctl所带来的变化。包括函数签名的调整——返回值类型由int变为long,并移除了inode参数,以及由此导致的应用程序与驱动程序中ioctl调用的不兼容问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.csdn.NET/cbl709/article/details/7295772  来源网址---谢谢分享----但是笔者可能忽略了函数的返回值类型为long

我在操作的时候发现在编译程序的时候有个警告

“ warning: initialization from incompatible pointer type [enabled by default]
: warning: (near initialization for ‘hello_fops.unlocked_ioctl’) [enabled by default]”

细致之后是发现是因为函数返回值类型是长整型long

今天调一个程序调了半天,发现应用程序的ioctl的cmd参数传送到驱动程序的ioctl发生改变。而根据《Linux设备驱动》这个cmd应该是不变的。因为在kernel 2.6.36 中已经完全删除了struct file_operations 中的ioctl 函数指针,取而代之的是unlocked_ioctl ,所以我怀疑二者是不是兼容的。上网查了一些资料,很多文章只是泛泛谈了一下,说在应用程序中ioctl是兼容的,不必变化。而在驱动程序中这个指针函数变了之后最大的影响是参数中少了inode ,所以应用程序ioctl是兼容的,但驱动程序中我们的ioctl函数必须变化,否则就会发生cmd参数的变化:

原来的驱动程序

static const struct file_operations globalmem_fops=
{
.owner=THIS_MODULE,
.llseek=globalmem_llseek,
.open=globalmem_open,
.read=globalmem_read,
.write=globalmem_write,
.ioctl=globalmem_ioctl,
.release=globalmem_release,
};

int globalmem_ioctl(struct inode* inode,struct file* filp, unsigned int cmd,unsigned long arg)

{

switch (cmd)

  {

   case:XXX:   ...

    ……

  }

}

改变后的

static const struct file_operations globalmem_fops=
{
.owner=THIS_MODULE,
.llseek=globalmem_llseek,
.open=globalmem_open,
.read=globalmem_read,
.write=globalmem_write,
.unlocked_ioctl=globalmem_ioctl,
.release=globalmem_release,
};

long globalmem_ioctl(struct file* filp, unsigned int cmd,unsigned long arg)//没有inode参数!返回值为long!

{

switch (cmd)

  {

   case:XXX:   ...

    ……

  }

}


总结:ioctl变为unlocked_ioctl时候有两个地方发生改变:一是返回值类型变为长整型;二是少了第一个参数inode;

  注意在file_operations中对应的改为unlocked_ioctl

### DS18B20 IOCTL 实现及相关问题 在 Linux 设备驱动程序中,`ioctl` 是一种常用的机制,用于实现用户空间内核空间之间的通信。对于 DS18B20 温度传感器而言,其 `ioctl` 接口通常被用来设置分辨率、触发温度转换以及读取特定的数据。 以下是关于 `ds18b20_ioctl` 的实现细节及其可能存在的问题: #### 1. **IOCTL 定义** 在用户空间的应用程序中,定义了与 DS18B20 相关的控制命令。这些命令通过 `_IOR`, `_IOW`, 或 `_IO` 来声明,具体取决于参数的方向性大小[^3]。 ```c #define GET_DS18B20_VAL_CMD _IOR('s', 1, int) ``` 上述宏表示一个从设备到用户的只读命令,其中 `'s'` 是魔术字符,`1` 是命令编号,`int` 表示传递给用户空间的数据类型。 #### 2. **Driver Implementation of ioctl** 在驱动程序中,`unlocked_ioctl` 函数负责处理来自用户空间的请求。以下是一个典型的实现框架: ```c static long ds18b20_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct ds18b20_dev *ds18b20 = filp->private_data; int ret = 0; switch (cmd) { case GET_DS18B20_VAL_CMD: ret = copy_to_user((void __user *)arg, &ds18b20->temperature, sizeof(int)); break; default: ret = -ENOTTY; /* Invalid command */ break; } return ret; } ``` 这里,`copy_to_user` 将内核缓冲区中的数据复制到用户空间地址 `(void __user *)arg` 中。如果命令不支持,则返回 `-ENOTTY` 错误码。 #### 3. **Resolution Setting via IOCTL** 根据引用文档[^4],可以通过 `ioctl` 命令来调整 DS18B20 的分辨率。这涉及向设备发送相应的配置命令并更新内部寄存器。 ```c case SET_DS18B20_RESOLUTION_CMD: if (get_user(resolution, (unsigned char __user *)arg)) { return -EFAULT; } ret = set_ds18b20_resolution(ds18b20, resolution); break; ``` 此处假设存在一个辅助函数 `set_ds18b20_resolution`,它能够根据指定的分辨率重新初始化硬件。 #### 4. **Potential Issues and Solutions** - **同步问题**: 如果多个进程尝试同时访问同一个 DS18B20 设备,可能会引发竞争条件。解决方案是在进入 `ioctl` 处理逻辑之前加锁: ```c mutex_lock(&ds18b20->lock); ... mutex_unlock(&ds18b20->lock); ``` - **错误处理不足**: 当某些操作失败时(如 GPIO 初始化),应确保资源得到适当清理以防止内存泄漏或未预期行为发生[^1]。 - **性能优化**: 对于频繁调用的操作(例如读取温度值),考虑引入缓存机制减少不必要的重复计算。 #### 5. **Example Code Snippet** 下面展示了一个完整的 `ioctl` 方法实现片段: ```c static long ds18b20_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct ds18b20_dev *ds18b20 = filp->private_data; int value; int ret = 0; mutex_lock(&ds18b20->lock); switch (cmd) { case GET_DS18B20_VAL_CMD: value = ds18b20_read_temperature(ds18b20); if (value < 0) { ret = value; goto out; } if (copy_to_user((void __user *)arg, &value, sizeof(value))) { ret = -EFAULT; goto out; } break; default: ret = -ENOTTY; break; } out: mutex_unlock(&ds18b20->lock); return ret; } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值