utils: add ioctl_macros module

Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Eric Callahan 2023-08-16 19:32:16 -04:00
parent 82dd2f3c1f
commit 65644bab8b
No known key found for this signature in database
GPG Key ID: 5A1EB336DFB4C71B
1 changed files with 77 additions and 0 deletions

View File

@ -0,0 +1,77 @@
# Methods to create IOCTL requests
#
# Copyright (C) 2023 Eric Callahan <arksine.code@gmail.com>
#
# This file may be distributed under the terms of the GNU GPLv3 license
from __future__ import annotations
import ctypes
from typing import Union, Type, TYPE_CHECKING
"""
This module contains of Python port of the macros avaialble in
"/include/uapi/asm-generic/ioctl.h" from the linux kernel.
"""
if TYPE_CHECKING:
IOCParamSize = Union[int, str, Type[ctypes._SimpleCData]]
_IOC_NRBITS = 8
_IOC_TYPEBITS = 8
# NOTE: The following could be platform specific.
_IOC_SIZEBITS = 14
_IOC_DIRBITS = 2
_IOC_NRMASK = (1 << _IOC_NRBITS) - 1
_IOC_TYPEMASK = (1 << _IOC_TYPEBITS) - 1
_IOC_SIZEMASK = (1 << _IOC_SIZEBITS) - 1
_IOC_DIRMASK = (1 << _IOC_DIRBITS) - 1
_IOC_NRSHIFT = 0
_IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
_IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
_IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS
# The constants below may also be platform specific
IOC_NONE = 0
IOC_WRITE = 1
IOC_READ = 2
def _check_value(val: int, name: str, maximum: int):
if val > maximum:
raise ValueError(f"Value '{val}' for '{name}' exceeds max of {maximum}")
def _IOC_TYPECHECK(param_size: IOCParamSize) -> int:
if isinstance(param_size, int):
return param_size
elif isinstance(param_size, bytearray):
return len(param_size)
elif isinstance(param_size, str):
ctcls = getattr(ctypes, param_size)
return ctypes.sizeof(ctcls)
return ctypes.sizeof(param_size)
def IOC(direction: int, cmd_type: int, cmd_number: int, param_size: int) -> int:
_check_value(direction, "direction", _IOC_DIRMASK)
_check_value(cmd_type, "cmd_type", _IOC_TYPEMASK)
_check_value(cmd_number, "cmd_number", _IOC_NRMASK)
_check_value(param_size, "ioc_size", _IOC_SIZEMASK)
return (
(direction << _IOC_DIRSHIFT) |
(param_size << _IOC_SIZESHIFT) |
(cmd_type << _IOC_TYPESHIFT) |
(cmd_number << _IOC_NRSHIFT)
)
def IO(cmd_type: int, cmd_number: int) -> int:
return IOC(IOC_NONE, cmd_type, cmd_number, 0)
def IOR(cmd_type: int, cmd_number: int, param_size: IOCParamSize) -> int:
return IOC(IOC_READ, cmd_type, cmd_number, _IOC_TYPECHECK(param_size))
def IOW(cmd_type: int, cmd_number: int, param_size: IOCParamSize) -> int:
return IOC(IOC_WRITE, cmd_type, cmd_number, _IOC_TYPECHECK(param_size))
def IOWR(cmd_type: int, cmd_number: int, param_size: IOCParamSize) -> int:
return IOC(IOC_READ | IOC_WRITE, cmd_type, cmd_number, _IOC_TYPECHECK(param_size))