1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
# SPDX-License-Identifier: MIT
import array
import fcntl
from typing import BinaryIO, Optional, Union
class IOCTL(object):
'''
Constructs and performs ioctl(s)
See include/asm-generic/ioctl.h
'''
NRBITS: int = 8
TYPEBITS: int = 8
SIZEBITS: int = 14
DIRBITS: int = 2
NRMASK: int = (1 << NRBITS) - 1
TYPEMASK: int = (1 << TYPEBITS) - 1
SIZEMASK: int = (1 << SIZEBITS) - 1
DIRMASK: int = (1 << DIRBITS) - 1
NRSHIFT: int = 0
TYPESHIFT: int = NRSHIFT + NRBITS
SIZESHIFT: int = TYPESHIFT + TYPEBITS
DIRSHIFT: int = SIZESHIFT + SIZEBITS
class Direction:
NONE = 0
WRITE = 1
READ = 2
def __init__(self, dir: int, ty: str, nr: int, size: int = 0, bad: bool = False) -> None:
assert self.Direction.NONE <= dir <= self.Direction.READ + self.Direction.WRITE
if dir == self.Direction.NONE:
size = 0
elif not bad:
assert size, size <= self.SIZEMASK
self.op = (
(dir << self.DIRSHIFT) |
(ord(ty) << self.TYPESHIFT) |
(nr << self.NRSHIFT) |
(size << self.SIZESHIFT)
)
def perform(self, fd: BinaryIO, buf: Optional[Union[str, bytes, 'array.array[int]']] = None) -> bytearray:
'''
Performs the ioctl
'''
size = self.unpack_size(self.op)
if buf is None:
buf = (size * '\x00').encode()
return bytearray(fcntl.ioctl(fd, self.op, buf)) # type: ignore
@classmethod
def unpack_dir(cls, nr: int) -> int:
return (nr >> cls.DIRSHIFT) & cls.DIRMASK
@classmethod
def unpack_type(cls, nr: int) -> int:
return (nr >> cls.TYPESHIFT) & cls.TYPEMASK
@classmethod
def unpack_nr(cls, nr: int) -> int:
return (nr >> cls.NRSHIFT) & cls.NRMASK
@classmethod
def unpack_size(cls, nr: int) -> int:
return (nr >> cls.SIZESHIFT) & cls.SIZEMASK
@classmethod
def IO(cls, ty: str, nr: int) -> 'IOCTL':
'''
Constructor for no direction
'''
return cls(cls.Direction.NONE, ty, nr)
@classmethod
def IOR(cls, ty: str, nr: int, size: int) -> 'IOCTL':
'''
Constructor for read
'''
return cls(cls.Direction.READ, ty, nr, size)
@classmethod
def IOW(cls, ty: str, nr: int, size: int) -> 'IOCTL':
'''
Constructor for write
'''
return cls(cls.Direction.WRITE, ty, nr, size)
@classmethod
def IORW(cls, ty: str, nr: int, size: int) -> 'IOCTL':
'''
Constructor for read & write
'''
return cls(cls.Direction.READ | cls.Direction.WRITE, ty, nr, size)
|