据我所知,ioctl数字由驱动程序很好地定义并在内核中注册。
我正在使用python中的一些代码来查询操纵杆状态。我看过this doc about joystick api,this doc about ioctl numbers和this one from python fcntl module。
我已经创建了一个用于测试和查询值的C程序,以及使用from here实现_IOR()
C宏的代码的python测试。
monolith@monolith ~/temp $ grep JSIOCGAXES /usr/include/* -r
/usr/include/linux/joystick.h:#define JSIOCGAXES _IOR('j', 0x11, __u8)
#include <stdio.h>
#include <linux/joystick.h>
#include <fcntl.h>
int main() {
int fd = open("/dev/input/js0", O_RDONLY);
printf("Ioctl Number: (int)%d (hex)%x\n", JSIOCGAXES, JSIOCGAXES);
char number;
ioctl(fd, JSIOCGAXES, &number);
printf("Number of axes: %d\n", number);
close(fd);
return 0;
}
monolith@monolith ~/temp $ ./test
Ioctl Number: (int)-2147390959 (hex)80016a11
Number of axes: 6
# check if _IOR results in the used ioctl number in C
>>> _IOR(ord('j'), 0x11, 'c')
-2147390959
>>> file = open("/dev/input/js0")
# use that integer
>>> fcntl.ioctl(file, -2147390959)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 14] Bad address
# ask what hex value is
>>> "%x" % -2147390959
'-7ffe95ef'
# WHY THIS HEX CONVERSION DIFFERS?
>>> fcntl.ioctl(file, -0x7ffe95ef)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 14] Bad address
# Use the hex value from the C program output
>>> fcntl.ioctl(file, 0x80016a11)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 14] Bad address
为什么我无法使用该ioctl号查询文件描述符? ioctl()
和fcntl()
函数采用文件描述符或实现fileno()
方法的对象,因此我从file
对象中删除了错误。
问题可能来自数字转换和类型,不知道......线索?
答案 0 :(得分:1)
这一切都归结为十六进制转换不同 - 插入十六进制C让你进入Python给你一个不同的数字:
>>> 0x80016a11
2147576337
我不确定为什么Python和C会给出不同的十六进制,但它可能至少部分与符号相关 - Python的'%x'
提供签名的十六进制值1 ,printf
s给出无符号2。
使用Python的十六进制值(-7ffe95ef
)可能会改善一些事情 - 或者更好的是,使用类似于C中的变量并保留转换错误:
op = _IOR(ord('j'), 0x11, 'c')
...
fcntl.ioctl(file, op)
答案 1 :(得分:1)
我将回答我自己的问题。
出于某种原因,从python使用ioctl()
获取值的唯一方法是发出以下代码:
>>> buf = array.array('h', [0])
>>> fcntl.ioctl(file.fileno(), 0x80016a11, buf)
0
>>> buf[0]
6
也就是说,使用缓冲区来结果。我应该重新阅读文档,并了解fcntl.ioctl(file.fileno(), 0x80016a11)
无效的原因。