获取Linux内核模块的ioctl上的ENOTTY

获取Linux内核模块的ioctl上的ENOTTY,linux,linux-kernel,kernel-module,ioctl,chardev,Linux,Linux Kernel,Kernel Module,Ioctl,Chardev,我定义了以下chardev: h 模块c static long device_ioctl( struct file* file, unsigned int ioctl_num, unsigned long ioctl_param) { ... } static int device_open(struct inode* inode, struct file* file

我定义了以下chardev:

h

模块c

static long device_ioctl(
                  struct file*   file,
                  unsigned int   ioctl_num,
                  unsigned long  ioctl_param)
{
    ...
}

static int device_open(struct inode* inode, struct file* file)
{
    ...
}

static int device_release(struct inode* inode, struct file* file)
{
    ...
}

struct file_operations Fops = {
    .open=device_open,
    .unlocked_ioctl= device_ioctl,
    .release=device_release
};

static int __init my_dev_init(void)
{
    register_chrdev(MAJOR_NUM, "MY_DEV", &Fops);
    ...
}
module_init(my_dev_init);
我的用户代码

ioctl(fd, IOCTL_MY_DEV1, 1);
总是以相同的错误失败:
ENOTTY

设备的ioctl不正确

我见过类似的问题: i、 e


但是他们的解决方案对我不起作用

ENOTTY
是在设备驱动程序没有注册要调用的ioctl函数时由内核发出的。恐怕您的函数注册不好,可能是因为您在
struct file\u operations
结构的
.unlocked\u ioctl
字段中注册了它

如果在函数的锁定版本中注册,可能会得到不同的结果。最可能的原因是inode被ioctl调用锁定(应该是这样的,以避免对同一设备同时执行
read
write
操作时出现争用情况)

很抱歉,我无法访问linux源代码树以获取要使用的字段的正确名称,但您肯定可以自己找到它

注 我注意到您使用了宏
\u IOW
,使用了主数字作为唯一标识符。这可能不是你想要的。
\u IOW
的第一个参数尝试确保ioctl调用获得唯一标识符。没有获取此类标识符的通用方法,因为这是在应用程序代码和内核代码之间创建的接口契约。因此,使用主数字是不好的做法,原因有二:

  • 多个设备(至少在linux中)可以共享相同的主编号(linux内核中的次要分配允许这一点),这使得设备的IOCTL之间可能发生冲突
  • 如果您更改了主要编号(您配置了一个已经分配了该编号的内核),您必须重新编译所有用户级软件以处理新的设备ioctl ID(如果您这样做,所有这些代码都会更改)
\u IOW
是一个很久以前(很久以前从linux内核诞生时)构建的宏,它试图解决这个问题,允许您为每个驱动程序选择不同的字符(但不依赖于其他内核参数,原因如上所述),以使具有ioctl调用的设备不会与另一个设备驱动程序的调用冲突。发生这种冲突的可能性很低,但发生这种情况时,可能会导致错误的机器状态(您已向错误的设备发出有效的、工作的ioctl调用)

古代unix(和早期linux)内核使用不同的字符来构建这些调用,因此,例如,
tty
驱动程序使用
'T'
作为
\u IO*
宏的参数,使用的scsi磁盘
'S'

我建议您选择一个随机数(不出现在linux内核清单的其他地方),然后在所有设备中使用它(您编写的驱动程序可能比内核中的驱动程序少),并为每个ioctl调用选择不同的ioctl id。用这种方式维护本地ioctl文件和已注册的ioctl要比猜测一个始终有效的值要好得多


另外,查看一下
\u IO*
宏的定义应该非常具有说明性
:)

您是否验证了是否调用了
设备\u ioctl()
?(在那里放置printk调用)@nos my
device\u ioctl()
未被调用,请放置一个只有
printk
的空正文您尚未正确注册ioctl调用的版本。。。试试那个锁着的。
ioctl(fd, IOCTL_MY_DEV1, 1);