os/uapi/
ioctl.rs

1//! ioctl 请求码定义
2//!
3//! 该模块定义了各种设备类型的 ioctl 请求码,遵循 Linux 标准。
4//!
5//! # ioctl 编码规则
6//!
7//! Linux ioctl 请求码通常使用 _IO, _IOR, _IOW, _IOWR 宏构造:
8//! - `_IO(type, nr)`: 无参数
9//! - `_IOR(type, nr, size)`: 读取数据
10//! - `_IOW(type, nr, size)`: 写入数据
11//! - `_IOWR(type, nr, size)`: 读写数据
12//!
13//! 参考:include/uapi/asm-generic/ioctl.h
14
15/// ioctl 方向:无数据传输
16pub const IOC_NONE: u32 = 0;
17/// ioctl 方向:写入(用户空间 -> 内核)
18pub const IOC_WRITE: u32 = 1;
19/// ioctl 方向:读取(内核 -> 用户空间)
20pub const IOC_READ: u32 = 2;
21
22/// ioctl 编码掩码
23pub const IOC_NRBITS: u32 = 8;
24pub const IOC_TYPEBITS: u32 = 8;
25pub const IOC_SIZEBITS: u32 = 14;
26pub const IOC_DIRBITS: u32 = 2;
27
28pub const IOC_NRSHIFT: u32 = 0;
29pub const IOC_TYPESHIFT: u32 = IOC_NRSHIFT + IOC_NRBITS;
30pub const IOC_SIZESHIFT: u32 = IOC_TYPESHIFT + IOC_TYPEBITS;
31pub const IOC_DIRSHIFT: u32 = IOC_SIZESHIFT + IOC_SIZEBITS;
32
33/// 构造 ioctl 请求码(无参数)
34pub const fn _IO(type_: u32, nr: u32) -> u32 {
35    _IOC(IOC_NONE, type_, nr, 0)
36}
37
38/// 构造 ioctl 请求码(读取数据)
39pub const fn _IOR(type_: u32, nr: u32, size: u32) -> u32 {
40    _IOC(IOC_READ, type_, nr, size)
41}
42
43/// 构造 ioctl 请求码(写入数据)
44pub const fn _IOW(type_: u32, nr: u32, size: u32) -> u32 {
45    _IOC(IOC_WRITE, type_, nr, size)
46}
47
48/// 构造 ioctl 请求码(读写数据)
49pub const fn _IOWR(type_: u32, nr: u32, size: u32) -> u32 {
50    _IOC(IOC_READ | IOC_WRITE, type_, nr, size)
51}
52
53/// ioctl 请求码构造函数
54pub const fn _IOC(dir: u32, type_: u32, nr: u32, size: u32) -> u32 {
55    (dir << IOC_DIRSHIFT) | (type_ << IOC_TYPESHIFT) | (nr << IOC_NRSHIFT) | (size << IOC_SIZESHIFT)
56}
57
58/// 从请求码中提取方向
59pub const fn _IOC_DIR(nr: u32) -> u32 {
60    (nr >> IOC_DIRSHIFT) & ((1 << IOC_DIRBITS) - 1)
61}
62
63/// 从请求码中提取类型
64pub const fn _IOC_TYPE(nr: u32) -> u32 {
65    (nr >> IOC_TYPESHIFT) & ((1 << IOC_TYPEBITS) - 1)
66}
67
68/// 从请求码中提取编号
69pub const fn _IOC_NR(nr: u32) -> u32 {
70    (nr >> IOC_NRSHIFT) & ((1 << IOC_NRBITS) - 1)
71}
72
73/// 从请求码中提取数据大小
74pub const fn _IOC_SIZE(nr: u32) -> u32 {
75    (nr >> IOC_SIZESHIFT) & ((1 << IOC_SIZEBITS) - 1)
76}
77
78// ========== 文件/通用 I/O 操作 ==========
79
80/// 设置/清除非阻塞 I/O 标志(int)
81pub const FIONBIO: u32 = 0x5421;
82
83/// 获取可读字节数(int)
84pub const FIONREAD: u32 = 0x541B;
85
86/// 设置/清除异步 I/O 通知(int)
87pub const FIOASYNC: u32 = 0x5452;
88
89/// 获取文件系统块大小(long)
90pub const FIGETBSZ: u32 = 2;
91
92// ========== 终端 ioctl(TTY/PTY)==========
93
94/// 终端 ioctl 魔数
95pub const TCGETS: u32 = 0x5401;
96pub const TCSETS: u32 = 0x5402;
97pub const TCSETSW: u32 = 0x5403;
98pub const TCSETSF: u32 = 0x5404;
99
100/// 获取终端窗口大小(struct winsize)
101pub const TIOCGWINSZ: u32 = 0x5413;
102
103/// 设置终端窗口大小(struct winsize)
104pub const TIOCSWINSZ: u32 = 0x5414;
105
106/// 获取终端进程组 ID(pid_t)
107pub const TIOCGPGRP: u32 = 0x540F;
108
109/// 设置终端进程组 ID(pid_t)
110pub const TIOCSPGRP: u32 = 0x5410;
111
112/// 获取输出队列中的字节数(int)
113pub const TIOCOUTQ: u32 = 0x5411;
114
115/// 获取输入队列中的字节数(int)
116pub const TIOCINQ: u32 = FIONREAD;
117
118/// 独占使用终端(void)
119pub const TIOCEXCL: u32 = 0x540C;
120
121/// 取消独占使用(void)
122pub const TIOCNXCL: u32 = 0x540D;
123
124/// 设置控制终端(void)- busybox init 需要
125pub const TIOCSCTTY: u32 = 0x540E;
126
127/// 查询可用的虚拟终端(int *)- 可选,用于 VT 切换
128pub const VT_OPENQRY: u32 = 0x5600;
129
130// ========== 网络 Socket ioctl ==========
131
132/// Socket ioctl 魔数
133pub const SIOCGIFNAME: u32 = 0x8910;
134
135/// 获取接口列表(struct ifconf)
136pub const SIOCGIFCONF: u32 = 0x8912;
137
138/// 获取接口地址(struct ifreq)
139pub const SIOCGIFADDR: u32 = 0x8915;
140
141/// 设置接口地址(struct ifreq)
142pub const SIOCSIFADDR: u32 = 0x8916;
143
144/// 获取接口标志(struct ifreq)
145pub const SIOCGIFFLAGS: u32 = 0x8913;
146
147/// 设置接口标志(struct ifreq)
148pub const SIOCSIFFLAGS: u32 = 0x8914;
149
150/// 获取接口广播地址(struct ifreq)
151pub const SIOCGIFBRDADDR: u32 = 0x8919;
152
153/// 设置接口广播地址(struct ifreq)
154pub const SIOCSIFBRDADDR: u32 = 0x891A;
155
156/// 获取接口网络掩码(struct ifreq)
157pub const SIOCGIFNETMASK: u32 = 0x891B;
158
159/// 设置接口网络掩码(struct ifreq)
160pub const SIOCSIFNETMASK: u32 = 0x891C;
161
162/// 获取接口 MTU(struct ifreq)
163pub const SIOCGIFMTU: u32 = 0x8921;
164
165/// 设置接口 MTU(struct ifreq)
166pub const SIOCSIFMTU: u32 = 0x8922;
167
168/// 获取接口硬件地址/MAC(struct ifreq)
169pub const SIOCGIFHWADDR: u32 = 0x8927;
170
171/// 设置接口硬件地址/MAC(struct ifreq)
172pub const SIOCSIFHWADDR: u32 = 0x8924;
173
174/// 获取接口索引(struct ifreq)
175pub const SIOCGIFINDEX: u32 = 0x8933;
176
177/// 根据索引获取接口名称(struct ifreq)
178pub const SIOCGIFNAME_BY_INDEX: u32 = 0x8910;
179
180// ========== 设备特定 ioctl ==========
181
182/// RTC(实时时钟)设备
183/// size = sizeof(struct rtc_time) = 9 * sizeof(int) = 36
184pub const RTC_RD_TIME: u32 = _IOR(b'p' as u32, 0x09, 36);
185pub const RTC_SET_TIME: u32 = _IOW(b'p' as u32, 0x0A, 36);
186
187/// RTC 时间结构体(对应 Linux struct rtc_time)
188///
189/// 参考:include/uapi/linux/rtc.h
190#[repr(C)]
191#[derive(Debug, Clone, Copy, Default)]
192pub struct RtcTime {
193    /// 秒 (0-59)
194    pub tm_sec: i32,
195    /// 分 (0-59)
196    pub tm_min: i32,
197    /// 时 (0-23)
198    pub tm_hour: i32,
199    /// 日 (1-31)
200    pub tm_mday: i32,
201    /// 月 (0-11, 注意是 0-based)
202    pub tm_mon: i32,
203    /// 年份 - 1900
204    pub tm_year: i32,
205    /// 星期 (0-6, 0=Sunday)
206    pub tm_wday: i32,
207    /// 年内第几天 (0-365)
208    pub tm_yday: i32,
209    /// 夏令时标志
210    pub tm_isdst: i32,
211}
212
213/// 块设备
214pub const BLKGETSIZE: u32 = _IO(0x12, 96);
215pub const BLKGETSIZE64: u32 = _IOR(0x12, 114, 8);
216pub const BLKFLSBUF: u32 = _IO(0x12, 97);
217
218// ========== 终端窗口大小结构体 ==========
219
220/// 终端窗口大小(用于 TIOCGWINSZ/TIOCSWINSZ)
221#[repr(C)]
222#[derive(Debug, Clone, Copy, Default)]
223pub struct WinSize {
224    /// 窗口行数(字符)
225    pub ws_row: u16,
226    /// 窗口列数(字符)
227    pub ws_col: u16,
228    /// 窗口宽度(像素,通常未使用)
229    pub ws_xpixel: u16,
230    /// 窗口高度(像素,通常未使用)
231    pub ws_ypixel: u16,
232}
233
234// ========== 终端属性结构体 (termios) ==========
235
236/// 特殊控制字符数量(Linux asm-generic 标准)
237pub const NCCS: usize = 19;
238
239/// 终端属性结构(用于 TCGETS/TCSETS)
240///
241/// 这是 Linux asm-generic/termbits.h 中定义的标准 termios 结构。
242/// RISC-V 架构使用 asm-generic 定义,NCCS=19。
243///
244/// 内存布局:
245/// - offset 0-15:  c_iflag, c_oflag, c_cflag, c_lflag (4 * u32 = 16 bytes)
246/// - offset 16:    c_line (u8 = 1 byte)
247/// - offset 17-35: c_cc\[19\] (19 * u8 = 19 bytes)
248/// - offset 36-39: c_ispeed (u32 = 4 bytes, 对齐到4字节边界)
249/// - offset 40-43: c_ospeed (u32 = 4 bytes)
250/// 总大小:44字节
251#[repr(C)]
252#[derive(Debug, Clone, Copy)]
253pub struct Termios {
254    /// 输入模式标志
255    pub c_iflag: u32,
256    /// 输出模式标志
257    pub c_oflag: u32,
258    /// 控制模式标志
259    pub c_cflag: u32,
260    /// 本地模式标志
261    pub c_lflag: u32,
262    /// 行规程
263    pub c_line: u8,
264    /// 特殊控制字符 [NCCS=19]
265    pub c_cc: [u8; NCCS],
266    /// 输入波特率(注意:musl 在此之前有3字节padding使其对齐到4字节边界)
267    pub c_ispeed: u32,
268    /// 输出波特率
269    pub c_ospeed: u32,
270}
271
272impl Termios {
273    /// 默认终端配置常量
274    ///
275    /// 提供标准的终端默认设置,适用于交互式 shell 和一般终端应用。
276    pub const DEFAULT: Self = Self {
277        // 输入模式:ICRNL (将 CR 转换为 NL)
278        c_iflag: 0x0100,
279        // 输出模式:OPOST | ONLCR (启用输出处理,将 NL 转换为 CR-NL)
280        c_oflag: 0x0001 | 0x0004,
281        // 控制模式:CS8 | CREAD (8位字符,允许接收)
282        c_cflag: 0x0030 | 0x0080,
283        // 本地模式:ISIG | ICANON | ECHO | ECHOE
284        c_lflag: 0x0001 | 0x0002 | 0x0008 | 0x0010,
285        // 行规程:0 (N_TTY)
286        c_line: 0,
287        // 特殊控制字符(使用常见默认值)
288        // 索引: 0=VINTR, 1=VQUIT, 2=VERASE, 3=VKILL, 4=VEOF, 5=VTIME, 6=VMIN,
289        //       7=VSWTC, 8=VSTART, 9=VSTOP, 10=VSUSP, 11=VEOL, 12=VREPRINT,
290        //       13=VDISCARD, 14=VWERASE, 15=VLNEXT, 16=VEOL2, 17-18=保留
291        c_cc: [
292            3,   // 0: VINTR (Ctrl-C)
293            28,  // 1: VQUIT (Ctrl-\)
294            127, // 2: VERASE (DEL)
295            21,  // 3: VKILL (Ctrl-U)
296            4,   // 4: VEOF (Ctrl-D)
297            0,   // 5: VTIME
298            1,   // 6: VMIN
299            0,   // 7: VSWTC
300            17,  // 8: VSTART (Ctrl-Q)
301            19,  // 9: VSTOP (Ctrl-S)
302            26,  // 10: VSUSP (Ctrl-Z)
303            0,   // 11: VEOL
304            18,  // 12: VREPRINT (Ctrl-R)
305            15,  // 13: VDISCARD (Ctrl-O)
306            23,  // 14: VWERASE (Ctrl-W)
307            22,  // 15: VLNEXT (Ctrl-V)
308            0,   // 16: VEOL2
309            0,   // 17: 保留
310            0,   // 18: 保留
311        ],
312        // 波特率:38400 (B38400 = 0x0000000f)
313        c_ispeed: 0x0000000f,
314        c_ospeed: 0x0000000f,
315    };
316}
317
318impl Default for Termios {
319    fn default() -> Self {
320        Self::DEFAULT
321    }
322}
323
324// ========== 网络接口结构体 ==========
325
326/// 最大接口名称长度
327pub const IFNAMSIZ: usize = 16;
328
329/// 接口请求结构(用于 SIOC* 操作)
330#[repr(C)]
331#[derive(Clone, Copy)]
332pub union IfreqIfru {
333    pub ifru_addr: [u8; 16],      // sockaddr
334    pub ifru_dstaddr: [u8; 16],   // sockaddr
335    pub ifru_broadaddr: [u8; 16], // sockaddr
336    pub ifru_netmask: [u8; 16],   // sockaddr
337    pub ifru_hwaddr: [u8; 16],    // sockaddr
338    pub ifru_flags: i16,
339    pub ifru_ivalue: i32,
340    pub ifru_mtu: i32,
341    pub ifru_map: [u8; 16],
342    pub ifru_slave: [u8; IFNAMSIZ],
343    pub ifru_newname: [u8; IFNAMSIZ],
344    pub ifru_data: usize, // void*
345}
346
347#[repr(C)]
348#[derive(Clone, Copy)]
349pub struct Ifreq {
350    pub ifr_name: [u8; IFNAMSIZ],
351    pub ifr_ifru: IfreqIfru,
352}
353
354/// 接口配置结构(用于 SIOCGIFCONF)
355#[repr(C)]
356pub struct Ifconf {
357    pub ifc_len: i32,
358    pub ifc_buf: usize, // void* 或 struct ifreq*
359}