문제

As far as I know, ioctl numbers are well defined by the drivers and registered in the kernel.

I was playing with some code in python for querying joystick states. I have read this doc about joystick api, this doc about ioctl numbers, and this one from python fcntl module.

I've created a C program for testing and querying values, and the python tests with code that I took from here for implementing the _IOR() C macro.

Kernel driver define:

monolith@monolith ~/temp $ grep JSIOCGAXES /usr/include/* -r
/usr/include/linux/joystick.h:#define JSIOCGAXES        _IOR('j', 0x11, __u8)

C program

#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;
}

C program Output:

monolith@monolith ~/temp $ ./test 
Ioctl Number: (int)-2147390959  (hex)80016a11
Number of axes: 6

Python output

# 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

Any ideas why I can't query the file descriptor with that ioctl number? ioctl() and fcntl() functions take a file descriptor or an object with the fileno() method implemented so I discart the error from the file object.

Maybe the problem comes with number conversion and types, no idea...clues?

도움이 되었습니까?

해결책 2

I'm going to answer my own question.

For some reason, the only way to get the value using ioctl() from python was issuing this code:

>>> buf = array.array('h', [0])
>>> fcntl.ioctl(file.fileno(), 0x80016a11, buf)
0
>>> buf[0]
6

That is, using a buffer to sotre the result. I should re-read the documentation and understand why fcntl.ioctl(file.fileno(), 0x80016a11) was not working.

다른 팁

This all boils down to the hex conversions being different - plugging the hex C gives you into Python gives you a different number:

>>> 0x80016a11
2147576337

I'm not sure why Python and C give different hex, but it is likely at least partially related to sign - Python's '%x' gives a signed hex value 1, printfs gives unsigned 2.

Using Python's hex value (-7ffe95ef) is likely to improve things - or, even better, use a variable like you do in C and keep the conversion errors out of it:

op = _IOR(ord('j'), 0x11, 'c')
...
fcntl.ioctl(file, op)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top