So, I want to call ioctl FBIOGET_FSCREENINFO
and get result. I have fbset (fbset - show and modify frame buffer device settings) result as source of truth. result of C code match with fbset. Result of Python code has mismatch in line_length
field. I have dumped raw bytes in both variants it same. On line_length
offset I have value 0x00000016
. But in Python it became to 0x16000000
, while in C it became to 0x00001600
. By 'became' I mean when I'm watching it in struct. According to fbset
, correct value is 0x00001600
(5632 in dec) At the same time, values of smem_len
and all others that previous to line_length
looks good. All of that values just flipped(in raw bytes string I see 00 00 42 00
for smem_len
but in variable it's value is 00 42 00 00
. And same for visual
: raw:02 00 00 00
, in var:00 00 00 02
). Mine raw bytes for both cases (result of ioctl call) 72 61 64 65 6f 6e 64 72 6d 66 62 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42 00 00 00 00 00 00 00 00 00 02 00 00 00 01 00 01 00 00 00 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
To map struct in Python I was using this source
C code:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
void print_hex_bytes(const void *ptr, size_t size) {
const unsigned char *byte_ptr = (const unsigned char *)ptr;
for (size_t i = 0; i < size; i++) {
printf("%02x ", byte_ptr[i]);
}
printf("\n");
}
int main()
{
int fbfd;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
/* Open the framebuffer device file for reading and writing. */
fbfd = open("/dev/fb0", O_RDWR);
if (fbfd == -1)
{
perror("Failed to open framebuffer device");
exit(1);
}
printf("The framebuffer device opened.\n");
/* Get variable screen information. */
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
{
close(fbfd);
perror("Failed to read fixed information");
exit(2);
}
printf("FIXED SCREEN INFOR total=%x\n", finfo);
print_hex_bytes(&finfo, sizeof(finfo));
print_hex_bytes(&finfo.line_length, sizeof(finfo.line_length));
printf("id=%s size=%d hex=%032x\n", finfo.id, sizeof(finfo.id), finfo.id);
printf("smem_start=%d size=%d hex=%016x\n", finfo.smem_start, sizeof(finfo.smem_start), finfo.smem_start);
printf("smem_len=%d size=%d hex=%08x\n", finfo.smem_len, sizeof(finfo.smem_len), finfo.smem_len);
printf("type=%d size=%d hex=%08x\n", finfo.type, sizeof(finfo.type), finfo.type);
printf("type_aux=%d size=%d hex=%08x\n", finfo.type_aux, sizeof(finfo.type_aux),finfo.type_aux);
printf("visual=%d size=%d hex=%08x\n", finfo.visual, sizeof(finfo.visual),finfo.visual);
printf("xpanstep=%d size=%d hex=%04x\n", finfo.xpanstep, sizeof(finfo.xpanstep),finfo.xpanstep);
printf("ypanstep=%d size=%d hex=%04x\n", finfo.ypanstep, sizeof(finfo.ypanstep),finfo.ypanstep);
printf("ywrapstep=%d size=%d hex=%04x\n", finfo.ywrapstep, sizeof(finfo.ywrapstep),finfo.ywrapstep);
printf("line_length=%d size=%d hex=%08x\n\n", finfo.line_length, sizeof(finfo.line_length), finfo.line_length);
printf("mmio_start=%d size=%d\n", finfo.mmio_start, sizeof(finfo.mmio_start));
printf("mmio_len=%d\n", finfo.mmio_len);
printf("accel=%d\n", finfo.accel);
printf("capabilities=%d\n", finfo.capabilities);
printf("reserved=%d\n", finfo.reserved);
/* Blank display. */
if (ioctl(fbfd, FBIOBLANK, 0))
{
close(fbfd);
perror("Failed to blank display");
exit(3);
}
/* Close file descriptor. */
close(fbfd);
return 0;
}
Python code:
import os
import fcntl
from construct import Struct, Container, Int16un, Int32un, Int64ul, Bytes
fb_bitfield_struct = Struct(
"offset" / Int32un, # type: ignore
"length" / Int32un, # type: ignore
"msb_right" / Int32un, # type: ignore
)
FBIOGET_VSCREENINFO_struct = {
"xres" : Int32un, # type: ignore # visible resolution
"yres" : Int32un, # type: ignore
"xres_virtual" : Int32un, # type: ignore # virtual resolution
"xoffset" : Int32un, # type: ignore # offset from virtual to visible
"yoffset" : Int32un, # type: ignore # resolution
"bits_per_pixel" : Int32un, # type: ignore # guess what
"grayscale" : Int32un, # type: ignore # 0 = color, 1 = grayscale, >1 = FOURCC
"red" : fb_bitfield_struct, # bitfield in fb mem if true color,
"green" : fb_bitfield_struct, # else only length is significant
"blue" : fb_bitfield_struct,
"transp" : fb_bitfield_struct, # transparency
"nonstd" : Int32un, # type: ignore # != 0 Non standard pixel format
"activate" : Int32un, # type: ignore # see FB_ACTIVATE_*
"height" : Int32un, # type: ignore # height of picture in mm
"width" : Int32un, # type: ignore # width of picture in mm
"accel_flags" : Int32un, # type: ignore # (OBSOLETE) see fb_info.flags
# Timing: All values in pixclocks, except pixclock (of course)
"pixclock" : Int32un, # type: ignore # pixel clock in ps (pico seconds)
"left_margin" : Int32un, # type: ignore # time from sync to picture
"right_margin" : Int32un, # type: ignore # time from picture to sync
"upper_margin" : Int32un, # type: ignore # time from sync to picture
"lower_margin" : Int32un, # type: ignore
"hsync_len" : Int32un, # type: ignore # length of horizontal sync
"vsync_len" : Int32un, # type: ignore # length of vertical sync
"sync" : Int32un, # type: ignore # see FB_SYNC_*
"vmode" : Int32un, # type: ignore # see FB_VMODE_*
"rotate" : Int32un, # type: ignore # angle we rotate counter clockwise
"colorspace" : Int32un, # type: ignore # colorspace for FOURCC-based modes
"reserved" : Int32un, # type: ignore # Reserved for future compatibility
}
FBIOGET_FSCREENINFO_struct = {
"id": Bytes(16), #identification string eg "TT Builtin"
"smem_start": Int64ul, # Start of frame buffer mem
# (physical address) */
"smem_len": Int32un, # Length of frame buffer mem
"type": Int32un, # see FB_TYPE_*
"type_aux": Int32un, # Interleave for interleaved Planes
"visual": Int32un, # see FB_VISUAL_*
"xpanstep": Int16un, # zero if no hardware panning
"ypanstep": Int16un, # zero if no hardware panning
"ywrapstep": Int16un, # zero if no hardware ywrap
"line_length": Int32un, # length of a line in bytes
"mmio_start": Int64ul, # Start of Memory Mapped I/O
# (physical address)
"mmio_len": Int32un, # Length of Memory Mapped I/O
"accel": Int32un, # Indicate to driver which
# specific chip/card we have
"capabilities": Int16un, # see FB_CAP_*
"reserved": Int16un, # Reserved for future compatibility
}
calls_map = {
"FBIOGET_VSCREENINFO": {
"address": 0x4600,
"format": FBIOGET_VSCREENINFO_struct
},
"FBIOGET_FSCREENINFO": {
"address": 0x4602,
"format": FBIOGET_FSCREENINFO_struct
}
}
def fbioctl_get(dev_path, call_name):
if call_name not in calls_map:
print(f'Call {call_name} not implemented')
return -1
fbfd = os.open(dev_path, os.O_RDWR)
if fbfd == -1:
print("Failed to open framebuffer device")
return -1
print("The framebuffer device opened.")
call_map = calls_map[call_name]
print(f'Addr={call_map["address"]}')
data_struct = Struct(**call_map["format"])
result_data = fcntl.ioctl(fbfd, call_map["address"], '\b0'*int(Struct.sizeof(data_struct)/2))
print(f'result={in_hex(result_data)} real_size={len(result_data)} size={Struct.sizeof(data_struct)}')
os.close(fbfd)
return data_struct.parse(result_data)
def in_hex(data):
b_data = data
if isinstance(data, int):
b_data = data.to_bytes((data.bit_length() + 7) // 8)
return ' '.join(f'{byte:02x}' for byte in b_data)
def main():
#vinfo = fbioctl_get('/dev/fb0', 'FBIOGET_VSCREENINFO')
finfo = fbioctl_get('/dev/fb0', 'FBIOGET_FSCREENINFO')
for key in FBIOGET_FSCREENINFO_struct.keys():
print(f'{key}={finfo[key]} hex={in_hex(finfo[key])}') # type: ignore
if __name__ == "__main__":
main()
What I want is to make Python and C code get correct result, same as fbset
. I tried to play with buffer length, types, but nothing helped.
You need to swap the byte order with construct.ByteSwapped(*subcon*)
.
Take a look at this.
Be warned, while all (as far as I know) desktops will need this, it may or may not work on ancient or server architecture. github issue
You are therefore much better off using this as it handles Endianness by itself