我有64位Enterprice SuSE 11 我有一个应用程序,打开一个HIDRAW设备并在其上运行ioctl函数,以获取此设备的原始信息,如下所示:
struct hidraw_devinfo devinfo;
int fd = open("/dev/hidraw0", 0);
int ret = ioctl(fd, HIDIOCGRAWINFO, &devinfo);
...
如果我在64位模式下编译该程序,则没有错误也没有问题,当我执行应用程序时,ioctl功能正常工作。
g++ main.cpp
如果我以32位模式编译该程序,也没有错误也没有问题。但是当我执行应用程序时,ioctl函数返回EINVAL错误(errno = 22,无效参数)
g++ -m32 main.cpp
问题是什么?
注意:
struct hidraw_devinfo
{
__u32 bustype;
__s16 vendor;
__s16 product;
}
答案 0 :(得分:3)
问题可能是您的程序传递给devinfo
函数的ioctl
结构不匹配。
我猜你的工作在64位系统上。因此,你的内核以64位运行,你正在与之交谈的内核模块(ioctl
)也是64位。
当您以64位编译用户程序时,内核模块和用户程序中的devinfo
定义是相同的。
以32位编译用户程序时,内核模块中的devinfo
定义与用户程序中的定义不同。实际上,在32位中,某些类型的大小会发生变化:主要是long
和指针。因此,您的程序创建一定大小的结构,内核模块以不同方式解释它接收的数据。内核模块可能无法理解您给它的值,因为它不会在您放置它的位置查找它。
解决方案是注意devinfo
结构的定义,以便在编译32位和64位时具有相同的二进制表示。
答案 1 :(得分:3)
Linux ioctl
定义和兼容性层是一个引人入胜的话题。
通常ioctl
定义使用一系列宏_IOW / _IOR等,它们将您的参数type-name作为参考,以及一个幻数和序数值,它们被赋予您的ioctl参数值(例如HIDIOCGRAWINFO
)。 type-name用于将sizeof(arg_type)
编码到定义中。这意味着 user 空间中使用的类型决定了ioctl
宏生成的值 - 即HIDIOCGRAWINFO可能会因包含条件而异。
这是32位和64位不同的第一点,sizeof
可能会有所不同,具体取决于打包,使用模糊的数据大小(例如长),但如果使用的话,尤其(并且不可避免地)指针参数。因此,在这种情况下,需要支持32位客户端需要的64位内核模块需要定义兼容性参数类型以匹配参数类型的32位等效的布局,从而匹配32位兼容的ioctl。这些32位等效定义使用名为compat
的内核工具/层。
在你的情况下,sizeof()
是相同的,所以这不是你正在采取的路径 - 但重要的是要了解可能发生的事情。
此外,内核配置可以定义CONFIG_COMPAT
,它会更改sys-call包装器(尤其是围绕用户/内核接口wrt ioctl
的代码),以减轻支持32-和64-的负担位。部分内容包括名为ioctl
的兼容性ioctl_compat
回调。
我看到的是CONFIG_COMPAT
定义了32位程序会生成代码,ioctl
回调ioctl_compat
,即使它可以} em>生成与64位相同的ioctl
值(例如在您的情况下)。因此驱动程序编写者需要确保ioctl_compat
处理两者特殊(不同)32位兼容ioctl
TYPE和正常“64位 - 或未更改32-位“类型。
因此,在仅32位和仅64位系统(没有CONFIG_COMPAT)上设计和测试的内核模块可能适用于32位和64位程序,但不适用于支持这两种程序的程序。
所以看看HID我看到这是在2.6.38中添加的:
http://lxr.linux.no/#linux+v2.6.38/drivers/hid/hidraw.c#L347