Skip to content

Commit c6a4a87

Browse files
emberianPaul Osborne
authored andcommitted
Completely revamp sys::ioctl to use cmr/ioctl's approach
This is more type-safe. Also, the old code wasn't cross-platform at all even though it claimed to be. It wasn't even portable across architectures on Linux.
1 parent 23dc9e0 commit c6a4a87

File tree

14 files changed

+2942
-0
lines changed

14 files changed

+2942
-0
lines changed

src/sys/ioctl/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
etc contains scripts for scraping the system for ioctls and the results of
2+
running said scripts.
3+
4+
platform contains platform-specific ioctl bindings and the definitions of the
5+
macros for encoding ioctl numbers etc.

src/sys/ioctl/etc/find_ioctls.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# PYTHONPATH=/home/cmr/llvm/tools/clang/bindings/python LD_LIBRARY_PATH=/usr/lib ./find_ioctls.py
2+
3+
import os
4+
import clang.cindex as c
5+
6+
header_paths = ["/usr/include"]
7+
8+
idx = c.Index.create()
9+
args = ['-E', '-x', 'c', '-I/usr/lib/clang/3.6.0/include/']
10+
options = c.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD | c.TranslationUnit.PARSE_SKIP_FUNCTION_BODIES | c.TranslationUnit.PARSE_INCOMPLETE
11+
12+
ioctls = []
13+
14+
for p in header_paths:
15+
for (dirp, dirn, fnames) in os.walk(p):
16+
for f in fnames:
17+
if f.endswith('.h'): # try to avoid C++ headers.
18+
tu = idx.parse(os.path.join(dirp, f), args=args,
19+
options=options)
20+
failed = False
21+
for diag in tu.diagnostics:
22+
if diag.severity > c.Diagnostic.Warning:
23+
failed = True
24+
break
25+
if failed:
26+
continue
27+
for cx in tu.cursor.walk_preorder():
28+
if cx.kind == c.CursorKind.MACRO_DEFINITION:
29+
if "IOC" in cx.spelling and cx.spelling.isupper():
30+
ioctls.append(list(tok.spelling for tok in cx.get_tokens()))
31+
32+
for ioctl in ioctls:
33+
print(ioctl)

src/sys/ioctl/etc/process_ioctls.py

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
import sys
2+
import os
3+
import operator
4+
5+
if len(sys.argv) != 2:
6+
sys.stderr.write("Wrong number of argmuments. Wanted one, the name of the\
7+
arch to use, got %s" % sys.argv)
8+
9+
arch = sys.argv[1]
10+
11+
f = open(os.path.join(arch, 'ioctl_list')) # found by find_ioctls.py
12+
m = open(os.path.join(arch, 'manually_found')) # found by the Mach V Eyeball
13+
i = open(os.path.join(arch, 'ignore_list')) # removed from the output of find_ioctls.py
14+
15+
print("// Initially generated by process_ioctls.py")
16+
17+
consts = {
18+
"mips": { "NONE": 1, "READ": 2, "WRITE": 4, "SIZEBITS": 13, "DIRBITS": 3},
19+
"powerpc": { "NONE": 1, "READ": 2, "WRITE": 4, "SIZEBITS": 13, "DIRBITS": 3},
20+
"x86": { "NONE": 0, "READ": 2, "WRITE": 1, "SIZEBITS": 14, "DIRBITS": 2},
21+
"x86_64": { "NONE": 0, "READ": 2, "WRITE": 1, "SIZEBITS": 14, "DIRBITS": 2},
22+
"arm": { "NONE": 0, "READ": 2, "WRITE": 1, "SIZEBITS": 14, "DIRBITS": 2},
23+
"aarch64": { "NONE": 0, "READ": 2, "WRITE": 1, "SIZEBITS": 14, "DIRBITS": 2},
24+
}
25+
26+
ioc_consts = {
27+
"SIOCPROTOPRIVATE": 0x89E0,
28+
"SIOCDEVPRIVATE": 0x89F0,
29+
"PCIIOC_BASE": (ord('P') << 24 | ord('C') << 16 | ord('I') << 8),
30+
"FIONREAD": 0x541B,
31+
"CZIOC": ord('M') << 8,
32+
"TIOCOUTQ": 0x5411,
33+
"TIOCM_CAR": 0x040,
34+
"TIOCM_RNG": 0x080,
35+
}
36+
37+
NONE = consts[arch]["NONE"]
38+
READ = consts[arch]["READ"]
39+
WRITE = consts[arch]["WRITE"]
40+
SIZEBITS = consts[arch]["SIZEBITS"]
41+
DIRBITS = consts[arch]["DIRBITS"]
42+
NRBITS = 8
43+
TYPEBITS = 8
44+
NRSHIFT = 0
45+
TYPESHIFT = NRSHIFT + NRBITS
46+
SIZESHIFT = TYPESHIFT + SIZEBITS
47+
DIRSHIFT = SIZESHIFT + DIRBITS
48+
NRMASK = (1 << NRBITS) - 1
49+
TYPEMASK = (1 << TYPEBITS) - 1
50+
SIZEMASK = (1 << SIZEBITS) - 1
51+
DIRMASK = (1 << DIRBITS) - 1
52+
53+
def decode(val):
54+
return (((val >> DIRSHIFT) & DIRMASK), ((val >> TYPESHIFT) & TYPEMASK),
55+
((val >> NRSHIFT) & NRMASK), ((val >> SIZESHIFT) & SIZEMASK))
56+
57+
ioctls = [] # ones we want to actually process
58+
59+
for ioctl in f:
60+
ioctls.append(eval(ioctl))
61+
for ioctl in m:
62+
ioctls.append(eval(ioctl))
63+
64+
mp = { "_IO": "none", "_IOR": "read", "_IOW": "write", "_IOWR": "readwrite",
65+
"DRM_IO": "none", "DRM_IOR": "read", "DRM_IOW": "write", "DRM_IOWR": "readwrite"}
66+
67+
tys = {
68+
"__uint8_t": "u8",
69+
"__uint16": "u16",
70+
"__uint32_t": "u32",
71+
"__uint64_t": "u64",
72+
"__int8_t": "i8",
73+
"__int16": "i16",
74+
"__int32_t": "i32",
75+
"__int64_t": "i64",
76+
"uint8_t": "u8",
77+
"uint16": "u16",
78+
"uint32_t": "u32",
79+
"uint64_t": "u64",
80+
"int8_t": "i8",
81+
"int16": "i16",
82+
"int32_t": "i32",
83+
"int64_t": "i64",
84+
"__u8": "u8",
85+
"__u16": "u16",
86+
"__u32": "u32",
87+
"__u64": "u64",
88+
"__s8": "i8",
89+
"__s16": "i16",
90+
"__s32": "i32",
91+
"__s64": "i64",
92+
"int": "::libc::c_int",
93+
"long": "::libc::c_long",
94+
"char": "::libc::c_char",
95+
"size_t": "::libc::size_t",
96+
}
97+
98+
utys = {
99+
"int": "::libc::c_uint",
100+
"long": "::libc::c_ulong",
101+
"char": "::libc::c_uchar",
102+
}
103+
104+
known_structs = ["input_id", "ff_effect", "ff_trigger", "ff_replay"]
105+
106+
manually_bound = ["EVIOCGNAME", "EVIOCGPHYS", "EVIOCGUNIQ", "EVIOCGPROP",
107+
"EVIOCGMTSLOTS", "EVIOCGKEY", "EVIOCGLED", "EVIOCGSND", "EVIOCGSW",
108+
"EVIOCGBIT", "EVIOCGABS", "EVIOCSABS", "EVIOCGRAB", "EVIOCREVOKE",
109+
"EVIOCSCLOCKID"]
110+
111+
bad_recovery = {}
112+
113+
def translate(ty):
114+
if len(ty) == 1:
115+
return tys.get(ty[0], "FIXME1<%s>" % ty)
116+
elif ty[-1] == '*':
117+
return "*mut " + translate(ty[:-1])
118+
elif len(ty) == 2:
119+
if ty[0] == "struct":
120+
return "/*struct*/ %s" % ty[1]
121+
elif ty[0] == "unsigned":
122+
return utys[ty[1]]
123+
else:
124+
return "FIXME2<%s>" % ty
125+
elif ty[-1] == ']':
126+
count = ty[-2]
127+
return "[%s; %s]" % (translate(ty[:-3]), count)
128+
else:
129+
return "FIXME3<%s>" % ty
130+
131+
def translate_type_code(ty):
132+
if ty[0] == "'":
133+
return "b" + ty
134+
else:
135+
return ty
136+
137+
def bad(name, val):
138+
if name in bad_recovery:
139+
process(bad_recovery[name])
140+
else:
141+
pval = None
142+
try:
143+
pval = int(val, 0)
144+
except:
145+
pass
146+
if pval is None:
147+
print("ioctl!(bad %s with %s);" % (name.lower(), val))
148+
else:
149+
(dr, ty, nr, sz) = decode(pval)
150+
if dr == NONE:
151+
print("ioctl!(none %s with %s, %s);" % (name.lower(), ty, nr))
152+
elif dr == READ:
153+
print("ioctl!(read %s with %s, %s; [u8; %s]);" %
154+
(name.lower(), ty, nr, sz));
155+
elif dr == WRITE:
156+
print("ioctl!(write %s with %s, %s; [u8; %s]);" %
157+
(name.lower(), ty, nr, sz));
158+
elif dr == READ|WRITE:
159+
print("ioctl!(readwrite %s with %s, %s; [u8; %s]);" %
160+
(name.lower(), ty, nr, sz));
161+
else:
162+
raise "This really shouldn't happen"
163+
164+
def bad2(name, val1, val2, op):
165+
if val1 in ioc_consts:
166+
val1 = ioc_consts[val1]
167+
else:
168+
val1 = int(val1, 0)
169+
170+
if val2 in ioc_consts:
171+
val2 = ioc_consts[val2]
172+
else:
173+
val2 = int(val2, 0)
174+
175+
bad(name, str(op(val1, val2)))
176+
177+
def process(ioctl):
178+
name = ioctl[0]
179+
rhs = ioctl[1:-1] # remove '#' or trailing comment
180+
cmd = rhs[0]
181+
body = rhs[2:-1]
182+
183+
if name in manually_bound:
184+
return
185+
elif cmd == "_IO":
186+
print("ioctl!(none %s with %s, %s);" % (name.lower(), translate_type_code(body[0]),
187+
body[2]))
188+
elif cmd == '_IOR' or cmd == '_IOW' or cmd == '_IOWR':
189+
if body[3] == ',':
190+
# this looks like _IOR(X, B, type...)
191+
first = body[0]
192+
second = body[2]
193+
ty = body[4:]
194+
ty = translate(ty)
195+
if "FIXME" in ty or "/*struct*/" in ty and not ty[11:] in known_structs:
196+
print("// ioctl!(%s %s with %s, %s; %s);" % (mp[cmd], name.lower(),
197+
translate_type_code(first), second, ty))
198+
else:
199+
print("ioctl!(%s %s with %s, %s; %s);" % (mp[cmd], name.lower(),
200+
translate_type_code(first), second, ty))
201+
elif body[3] == '+':
202+
first = body[0]
203+
second = " ".join(body[2:5])
204+
ty = body[6:]
205+
ty = translate(ty)
206+
if "FIXME" in ty or "/*struct*/" in ty and not ty[11:] in known_structs:
207+
print("// ioctl!(%s %s with %s, %s; %s);" % (mp[cmd], name.lower(),
208+
translate_type_code(first), second, ty))
209+
else:
210+
print("ioctl!(%s %s with %s, %s; %s);" % (mp[cmd], name.lower(),
211+
translate_type_code(first), second, ty))
212+
# We probably have _IOR(X, B + C, type...)
213+
else:
214+
raise "This really shouldn't happen"
215+
elif cmd == "DRM_IO" or cmd == "DRM_IOR" or cmd == "DRM_IOW" or cmd == "DRM_IOWR":
216+
# rewrite into "canonical" version.
217+
process([name, cmd[3:], "(", "DRM_IOCTL_BASE", ","] + rhs[2:] + ["#"])
218+
elif len(rhs) == 1: # single constant :(
219+
bad(name.lower(), ioc_consts.get(rhs[0], rhs[0]))
220+
elif len(rhs) == 3 and rhs[0] == "(": # single constant in parens
221+
bad(name.lower(), ioc_consts.get(rhs[1], rhs[1]))
222+
elif rhs[2] == "+": # we have the sum of two constants
223+
try:
224+
bad2(name.lower(), rhs[1], rhs[3], operator.add)
225+
except:
226+
bad(name.lower(), " ".join(rhs[1:-1]))
227+
elif rhs[2] == "|": # we have an or of two constants (eugh)
228+
try:
229+
bad2(name.lower(), rhs[1], rhs[3], operator.or_)
230+
except:
231+
bad(name.lower(), " ".join(rhs[1:-1]))
232+
else:
233+
print("// TODO #define %s %s" % (name, " ".join(rhs)))
234+
235+
for ioctl in ioctls:
236+
process(ioctl)

src/sys/ioctl/etc/x86_64/ignore_list

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
['ATMIOC_AREQUIPA', '0xc0', '/* Application requested IP over ATM, glob. u. */']
2+
['ATMIOC_BACKEND', '0x90', '/* ATM generic backend ioctls, u. per backend */']
3+
['ATMIOC_BACKEND_END', '0xaf', '/* 0xb0-0xbf: Reserved for future use */']
4+
['ATMIOC_CLIP', '0xe0', '/* Classical IP over ATM control, globally u. */']
5+
['ATMIOC_CLIP_END', '0xef', '#']
6+
['ATMIOC_ITF', '0x80', '/* Interface ioctls, globally unique */']
7+
['ATMIOC_ITF_END', '0x8f', '#']
8+
['ATMIOC_LANE', '0xd0', '/* LAN Emulation, globally unique */']
9+
['ATMIOC_MPOA', '0xd8', '/* MPOA, globally unique */']
10+
['ATMIOC_PHYCOM', '0x00', '/* PHY device common ioctls, globally unique */']
11+
['ATMIOC_PHYCOM_END', '0x0f', '#']
12+
['ATMIOC_PHYPRV', '0x30', '/* PHY dev private ioctls, unique per driver */']
13+
['ATMIOC_PHYPRV_END', '0x4f', '#']
14+
['ATMIOC_PHYTYP', '0x10', '/* PHY dev type ioctls, unique per PHY type */']
15+
['ATMIOC_PHYTYP_END', '0x2f', '#']
16+
['ATMIOC_SARCOM', '0x50', '/* SAR device common ioctls, globally unique */']
17+
['ATMIOC_SARCOM_END', '0x50', '#']
18+
['ATMIOC_SARPRV', '0x60', '/* SAR dev private ioctls, unique per driver */']
19+
['ATMIOC_SARPRV_END', '0x7f', '#']
20+
['ATMIOC_SPECIAL', '0xf0', '/* Special-purpose controls, globally unique */']
21+
['ATMIOC_SPECIAL_END', '0xff', '#']
22+
['BASE_VIDIOC_PRIVATE', '192', '/* 192-255 are private */']
23+
['BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL', '2', '#']
24+
['BTRFS_IOCTL_DEV_REPLACE_CMD_START', '0', '#']
25+
['BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS', '1', '#']
26+
['BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS', '0', '#']
27+
['BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID', '1', 'struct']
28+
['BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED', '2', 'struct']
29+
['BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED', '1', '#']
30+
['BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR', '0', '#']
31+
['BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED', '3', '#']
32+
['BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED', '2', '#']
33+
['BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED', '0', '#']
34+
['BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED', '1', '#']
35+
['BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED', '4', 'struct']
36+
['BTRFS_IOCTL_MAGIC', '0x94', '#']
37+
['CCISS_IOC_MAGIC', "'B'", 'typedef']
38+
['CM_IOC_MAGIC', "'c'", '#']
39+
['CM_IOC_MAXNR', '255', '#']
40+
['COOKED_IOCTL', '1', '#']
41+
['CUSE_UNRESTRICTED_IOCTL', '(', '1', '<<', '0', ')', '/**\n * Release flags\n */']
42+
['C_CM_IOCTL', '0x02', '/* re-read CH_CTRL */']
43+
['C_CM_IOCTLM', '0x04', '/* RS-232 outputs change */']
44+
['C_CM_IOCTLW', '0x03', '/* re-read CH_CTRL, intr when done */']
45+
['C_IN_IOCTLW', '0x00020000', '/* I/O control w/ wait */']
46+
['DECNET_IOCTL_BASE', '0x89', '/* PROTOPRIVATE range */']
47+
['DM_IOCTL', '0xfd', '#']
48+
['DRM_IOCTL_BASE', "'d'", '#']
49+
['DTV_IOCTL_MAX_MSGS', '64', 'struct']
50+
['FSL_HV_IOCTL_TYPE', '0xAF', '/* Restart another partition */']
51+
['FUSE_IOCTL_MAX_IOV', '256', '/**\n * Poll flags\n *\n * FUSE_POLL_SCHEDULE_NOTIFY: request poll notify\n */']
52+
['GIGASET_IOCTL', '0x47', '/* enable/disable device control via character device (lock out ISDN subsys) */']
53+
['GNUTLS_E_CRYPTODEV_IOCTL_ERROR', '-', '211', '#']
54+
['IB_IOCTL_MAGIC', '0x1b', '#']
55+
['IOCB_FLAG_RESFD', '(', '1', '<<', '0', ')', '/* read() from /dev/aio returns these structures. */']
56+
['MGSL_MAGIC_IOC', "'m'", '#']
57+
['MMC_IOC_MAX_BYTES', '(', '512L', '*', '256', ')', '#']
58+
['MMTIMER_IOCTL_BASE', "'m'", '#']
59+
['MTRR_IOCTL_BASE', "'M'", '/* Warning: this structure has a different order from i386\n on x86-64. The 32bit emulation code takes care of that.\n But you need to use this for 64bit, otherwise your X server\n will break. */']
60+
['PH_IOC_MAGIC', "'p'", '#']
61+
['PP_IOCTL', "'p'", '/* Set mode for read/write (e.g. IEEE1284_MODE_EPP) */']
62+
['RFKILL_IOC_MAGIC', "'R'", '#']
63+
['RFKILL_IOC_NOINPUT', '1', '#']
64+
['UBI_CTRL_IOC_MAGIC', "'o'", '/* Attach an MTD device */']
65+
['UINPUT_IOCTL_BASE', "'U'", '#']
66+
['USBTMC_IOC_NR', '91', '#']
67+
['USB_SUBCLASS_AUDIOCONTROL', '0x01', '#']
68+
['VIOCD_MAJOR', '113', '#']
69+
['WATCHDOG_IOCTL_BASE', "'W'", 'struct']
70+
['_ASM_GENERIC_IOCTL_H', "/* ioctl command encoding: 32 bits total, command in lower 16 bits,\n * size of the parameter structure in the lower 14 bits of the\n * upper 16 bits.\n * Encoding the size of the parameter structure in the ioctl request\n * is useful for catching programs compiled with old versions\n * and to avoid overwriting user space outside the user buffer area.\n * The highest 2 bits are reserved for indicating the ``access mode''.\n * NOTE: This limits the max parameter size to 16kB -1 !\n */"]
71+
['_EVENT_HAVE_SYS_IOCTL_H', '1', '/* Define to 1 if you have the <sys/mman.h> header file. */']
72+
['_IOC', '(', 'dir', ',', 'type', ',', 'nr', ',', 'size', ')', '(', '(', '(', 'dir', ')', '<<', '_IOC_DIRSHIFT', ')', '|', '(', '(', 'type', ')', '<<', '_IOC_TYPESHIFT', ')', '|', '(', '(', 'nr', ')', '<<', '_IOC_NRSHIFT', ')', '|', '(', '(', 'size', ')', '<<', '_IOC_SIZESHIFT', ')', ')', '#']
73+
['_IOC_DIR', '(', 'nr', ')', '(', '(', '(', 'nr', ')', '>>', '_IOC_DIRSHIFT', ')', '&', '_IOC_DIRMASK', ')', '#']
74+
['_IOC_DIRBITS', '2', '#']
75+
['_IOC_DIRMASK', '(', '(', '1', '<<', '_IOC_DIRBITS', ')', '-', '1', ')', '#']
76+
['_IOC_DIRSHIFT', '(', '_IOC_SIZESHIFT', '+', '_IOC_SIZEBITS', ')', '/*\n * Direction bits, which any architecture can choose to override\n * before including this file.\n */']
77+
['_IOC_NONE', '0U', '#']
78+
['_IOC_NR', '(', 'nr', ')', '(', '(', '(', 'nr', ')', '>>', '_IOC_NRSHIFT', ')', '&', '_IOC_NRMASK', ')', '#']
79+
['_IOC_NRBITS', '8', '#']
80+
['_IOC_NRMASK', '(', '(', '1', '<<', '_IOC_NRBITS', ')', '-', '1', ')', '#']
81+
['_IOC_NRSHIFT', '0', '#']
82+
['_IOC_READ', '2U', '#']
83+
['_IOC_SIZE', '(', 'nr', ')', '(', '(', '(', 'nr', ')', '>>', '_IOC_SIZESHIFT', ')', '&', '_IOC_SIZEMASK', ')', '/* ...and for the drivers/sound files... */']
84+
['_IOC_SIZEBITS', '14', '#']
85+
['_IOC_SIZEMASK', '(', '(', '1', '<<', '_IOC_SIZEBITS', ')', '-', '1', ')', '#']
86+
['_IOC_SIZESHIFT', '(', '_IOC_TYPESHIFT', '+', '_IOC_TYPEBITS', ')', '#']
87+
['_IOC_TYPE', '(', 'nr', ')', '(', '(', '(', 'nr', ')', '>>', '_IOC_TYPESHIFT', ')', '&', '_IOC_TYPEMASK', ')', '#']
88+
['_IOC_TYPEBITS', '8', '/*\n * Let any architecture override either of the following before\n * including this file.\n */']
89+
['_IOC_TYPECHECK', '(', 't', ')', '(', 'sizeof', '(', 't', ')', ')', '/* used to create numbers */']
90+
['_IOC_TYPEMASK', '(', '(', '1', '<<', '_IOC_TYPEBITS', ')', '-', '1', ')', '#']
91+
['_IOC_TYPESHIFT', '(', '_IOC_NRSHIFT', '+', '_IOC_NRBITS', ')', '#']
92+
['_IOC_WRITE', '1U', '#']
93+
['_SIOC_DIR', '_IOC_DIR', '#']
94+
['_SIOC_NONE', '_IOC_NONE', '#']
95+
['_SIOC_READ', '_IOC_READ', '#']
96+
['_SIOC_SIZE', '_IOC_SIZE', '#']
97+
['_SIOC_WRITE', '_IOC_WRITE', '#']
98+
['UBI_IOC_MAGIC', "'o'", '/* Create an UBI volume */']
99+
['UBI_VOL_IOC_MAGIC', "'O'", "/* Start UBI volume update\n * Note: This actually takes a pointer (__s64*), but we can't change\n * that without breaking the ABI on 32bit systems\n */"]
100+
['IPMI_IOC_MAGIC', "'i'", '/* Messages sent to the interface are this format. */']
101+
['PACKET_IOCTL_MAGIC', '(', "'X'", ')', '#']
102+
['PCIIOC_BASE', '(', "'P'", '<<', '24', '|', "'C'", '<<', '16', '|', "'I'", '<<', '8', ')', '#']
103+
['SNAPSHOT_IOC_MAGIC', "'3'", '#']
104+
['SNAPSHOT_IOC_MAXNR', '20', '#']
105+
['SIOC_IN', 'IOC_IN', '#']
106+
['SIOC_INOUT', 'IOC_INOUT', '#']
107+
['SIOC_OUT', 'IOC_OUT', '#']
108+
['SIOC_VOID', 'IOC_VOID', '#']
109+
['SPI_IOC_MAGIC', "'k'", "/**\n * struct spi_ioc_transfer - describes a single SPI transfer\n * @tx_buf: Holds pointer to userspace buffer with transmit data, or null.\n *\tIf no data is provided, zeroes are shifted out.\n * @rx_buf: Holds pointer to userspace buffer for receive data, or null.\n * @len: Length of tx and rx buffers, in bytes.\n * @speed_hz: Temporary override of the device's bitrate.\n * @bits_per_word: Temporary override of the device's wordsize.\n * @delay_usecs: If nonzero, how long to delay after the last bit transfer\n *\tbefore optionally deselecting the device before the next transfer.\n * @cs_change: True to deselect device before starting the next transfer.\n *\n * This structure is mapped directly to the kernel spi_transfer structure;\n * the fields have the same meanings, except of course that the pointers\n * are in a different address space (and may be of different sizes in some\n * cases, such as 32-bit i386 userspace over a 64-bit x86_64 kernel).\n * Zero-initialize the structure, including currently unused fields, to\n * accommodate potential future updates.\n *\n * SPI_IOC_MESSAGE gives userspace the equivalent of kernel spi_sync().\n * Pass it an array of related transfers, they'll execute together.\n * Each transfer may be half duplex (either direction) or full duplex.\n *\n *\tstruct spi_ioc_transfer mesg[4];\n *\t...\n *\tstatus = ioctl(fd, SPI_IOC_MESSAGE(4), mesg);\n *\n * So for example one transfer might send a nine bit command (right aligned\n * in a 16-bit word), the next could read a block of 8-bit data before\n * terminating that command by temporarily deselecting the chip; the next\n * could send a different nine bit command (re-selecting the chip), and the\n * last transfer might write some register values.\n */"]
110+
['CZIOC', '(', "'M'", '<<', '8', ')', '#']
111+
['IOC_IN', '(', '_IOC_WRITE', '<<', '_IOC_DIRSHIFT', ')', '#']
112+
['IOC_INOUT', '(', '(', '_IOC_WRITE', '|', '_IOC_READ', ')', '<<', '_IOC_DIRSHIFT', ')', '#']
113+
['IOC_OUT', '(', '_IOC_READ', '<<', '_IOC_DIRSHIFT', ')', '#']

0 commit comments

Comments
 (0)