Files
ViperOS/VKernel/Kernel/drivers/devfs/devfs.vp
T
TermiNexus dcb7c5c2c0 chore(ViperOS): 落库内核侧进行中的改动(26 文件,+1573/-1805)
内容由用户产出,本次仅代为提交、未做任何语义修改;含 static 修饰符前置迁移等(新增 static 前缀 16 行)。提交消息为中性描述——如需更精确的说明请 amend。
2026-09-28 15:24:52 +08:00

451 lines
15 KiB
Plaintext

import drivers.serial.uart.serial as serial
import string
import viperlib
define MAX_FILE_DESCRIPTORS = 64
define MAX_DEVICE_FILES = 32
define MAX_DIRECTORIES = 16
define PATH_BUFFER_SIZE = 256
directories: [MAX_DIRECTORIES]devfs_directory = [0]
static directory_count: int = 0
files: [MAX_DEVICE_FILES]devfs_file = [0]
static file_count: int = 0
class _fd_table:
file: devfs_file*
flags: int
fd_table: [MAX_FILE_DESCRIPTORS]_fd_table = [0]
class devfs_directory:
name: [64]char
parent: devfs_directory*
@staticmethod
def find(path: const str, root_directory: devfs_directory*) -> devfs_directory*:
if not path or string.strchr(path, '/') != path: return None
if not root_directory: return None
current_dir: devfs_directory* = root_directory
result: [PATH_BUFFER_SIZE]str
token = string.split(path, "/", result, PATH_BUFFER_SIZE)
# `for i in result` 按 NULL 终止语义遍历(i8* 元素,split 尾哨兵 NULL 停):
# 编译器 _handle_array_iter 已实现"长度上限 + 解引用为空提前终止"。
for i in result:
found: bool = False
for d in range(directory_count):
dirp: devfs_directory = &directories[d]
if dirp.parent == current_dir and string.samestr(dirp.name, i):
current_dir = dirp
found = True
break
if not found: return None
return current_dir
@staticmethod
def find_child(name: const str, parent: devfs_directory*) -> devfs_directory*:
for d in range(directory_count):
dirp: devfs_directory = &directories[d]
if dirp.parent == parent and string.samestr(dirp.name, name):
return dirp
return None
@staticmethod
def list_subdirs(dir_ptr: devfs_directory*, buffer: str, size: uint32, pos: int) -> int:
for d in range(directory_count):
dirp: devfs_directory = &directories[d]
if dirp.parent == dir_ptr:
name_len: int = string.strlen(dirp.name)
if pos + name_len + 1 > size:
break
string.strcpy(buffer + pos, dirp.name)
pos += name_len
buffer[pos] = '\n'
pos += 1
return pos
virtual class devfs_file:
name: [64]char
private_data: rawptr
parent_dir: devfs_directory*
@staticmethod
def find_in_dir(file_name: const str, dir_ptr: devfs_directory*) -> devfs_file*:
for f in range(file_count):
fp: devfs_file* = &files[f]
if fp.parent_dir == dir_ptr and string.samestr(fp.name, file_name):
return fp
return None
@staticmethod
def list_in_dir(dir_ptr: devfs_directory*, buffer: str, size: uint32, pos: int) -> int:
for f in range(file_count):
filep: devfs_file* = &files[f]
if filep.parent_dir == dir_ptr:
name_len: int = string.strlen(filep.name)
if pos + name_len + 1 > size:
break
string.strcpy(buffer + pos, filep.name)
pos += name_len
buffer[pos] = '\n'
pos += 1
return pos
def open(self, path: const str, flags: int) -> int: return 0
def close(self, fd: int) -> int: return 0
def read(self, fd: int, buffer: rawptr, size: uint32) -> int: return 0
def write(self, fd: int, buffer: const rawptr, size: uint32) -> int: return 0
def ioctl(self, fd: int, request: int, arg: rawptr) -> int: return 0
class _DevFSObject:
root_directory: devfs_directory*
def __init__(self):
global directory_count, file_count
self.root_directory = None
directory_count = 0
file_count = 0
string.memset(&directories, 0, devfs_directory.__sizeof__() * MAX_DIRECTORIES)
string.memset(&files, 0, devfs_file.__sizeof__() * MAX_DEVICE_FILES)
string.memset(&fd_table, 0, _fd_table.__sizeof__() * MAX_FILE_DESCRIPTORS)
def create_single_dir(self, parent: devfs_directory*, dir_name: const str) -> devfs_directory*:
global directory_count
if not parent or not dir_name: return None
if directory_count >= MAX_DIRECTORIES: return None
if string.strlen(dir_name) >= 64: return None
new_dir: devfs_directory* = &directories[directory_count]
directory_count += 1
string.strcpy(new_dir.name, dir_name)
new_dir.parent = parent
return new_dir
def find_or_create_directory(self, path: const str) -> devfs_directory*:
global directory_count
if not path or string.samestr(path, "/"): return None
if not self.root_directory:
self.root_directory = &directories[directory_count]
directory_count += 1
string.strcpy(self.root_directory.name, "")
self.root_directory.parent = None
current: devfs_directory* = self.root_directory
buf: [PATH_BUFFER_SIZE]char
string.memset(&buf, 0, PATH_BUFFER_SIZE)
buf_idx: int = 0
p: int = 0
if path[p] == '/': p += 1
while path[p] != '\0':
if path[p] == '/':
if buf_idx > 0:
found_child: devfs_directory* = devfs_directory.find_child(buf, current)
if not found_child:
found_child = self.create_single_dir(current, buf)
if not found_child: return None
current = found_child
string.memset(&buf, 0, PATH_BUFFER_SIZE)
buf_idx = 0
p += 1
else:
buf[buf_idx] = path[p]
buf_idx += 1
p += 1
if buf_idx > 0:
found_child: devfs_directory* = devfs_directory.find_child(buf, current)
if not found_child:
found_child = self.create_single_dir(current, buf)
if not found_child: return None
current = found_child
return current
def init(self) -> int:
self.create_directory("/dev")
self.create_directory("/dev/input")
return 0
def create_directory(self, path: const str) -> int:
dir_ptr: devfs_directory* = self.find_or_create_directory(path)
return 0 if dir_ptr else -1
def create_file(self, path: const str, file_ptr: devfs_file*, private_data: rawptr) -> int:
global file_count
path_copy: [PATH_BUFFER_SIZE]char
string.memset(&path_copy, 0, PATH_BUFFER_SIZE)
string.strcpy(&path_copy, path)
last_slash: str = string.strrchr(path_copy, '/')
if not last_slash: return -1
last_slash[0] = '\0'
dir_path = path_copy
file_name: str = last_slash + 1
dir_ptr: devfs_directory* = self.find_or_create_directory(dir_path)
if not dir_ptr: return -1
if devfs_file.find_in_dir(file_name, dir_ptr): return -1
if file_count >= MAX_DEVICE_FILES: return -1
if file_ptr:
string.strcpy(file_ptr.name, file_name)
file_ptr.private_data = private_data
file_ptr.parent_dir = dir_ptr
files[file_count] = file_ptr
else:
new_file: devfs_file* = &files[file_count]
string.strcpy(new_file.name, file_name)
new_file.private_data = private_data
new_file.parent_dir = dir_ptr
file_count += 1
return 0
def open(self, path: const str, flags: int) -> int:
path_copy: [PATH_BUFFER_SIZE]char
string.memset(&path_copy, 0, PATH_BUFFER_SIZE)
string.strcpy(&path_copy, path)
last_slash: str = string.strrchr(path_copy, '/')
if not last_slash: return -1
last_slash[0] = '\0'
dir_path = path_copy
file_name: str = last_slash + 1
dir_ptr: devfs_directory* = devfs_directory.find(dir_path, self.root_directory)
if not dir_ptr: return -1
file_ptr: devfs_file* = devfs_file.find_in_dir(file_name, dir_ptr)
if not file_ptr: return -1
fd: int = -1
for i in range(MAX_FILE_DESCRIPTORS):
if not fd_table[i].file:
fd = i
break
if fd == -1: return -1
ret: int = file_ptr.open(path, flags)
if ret != 0: return ret
fd_table[fd].file = file_ptr
fd_table[fd].flags = flags
return fd
def close(self, fd: int) -> int:
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
return -1
file_ptr: devfs_file* = fd_table[fd].file
file_ptr.close(fd)
fd_table[fd].file = None
fd_table[fd].flags = 0
return 0
def read(self, fd: int, buffer: rawptr, size: uint32) -> int:
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
return -1
file_ptr: devfs_file* = fd_table[fd].file
return file_ptr.read(fd, buffer, size)
def write(self, fd: int, buffer: const rawptr, size: uint32) -> int:
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
return -1
file_ptr: devfs_file* = fd_table[fd].file
return file_ptr.write(fd, buffer, size)
def ioctl(self, fd: int, cmd: uint32, arg: rawptr) -> int:
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
return -1
file_ptr: devfs_file* = fd_table[fd].file
return file_ptr.ioctl(fd, cmd, arg)
def list_directory(self, path: const str,
buffer: str,
size: uint32) -> int:
dir_ptr: devfs_directory* = devfs_directory.find(path, self.root_directory)
if not dir_ptr or not buffer or size == 0: return -1
pos: int = devfs_directory.list_subdirs(dir_ptr, buffer, size, 0)
pos = devfs_file.list_in_dir(dir_ptr, buffer, size, pos)
return pos
DevFSObject: _DevFSObject*
_DevFSObject_instance: _DevFSObject
def devfs_init() -> int:
global DevFSObject, _DevFSObject_instance
DevFSObject = &_DevFSObject_instance
_DevFSObject_instance = _DevFSObject()
DevFSObject.init()
return 0
def devfs_create_directory(path: const str) -> int:
return DevFSObject.create_directory(path)
def devfs_create_file(path: const str, file_ptr: devfs_file*, private_data: rawptr) -> int:
return DevFSObject.create_file(path, file_ptr, private_data)
def devfs_open(path: const str, flags: int) -> int:
return DevFSObject.open(path, flags)
def devfs_close(fd: int) -> int:
return DevFSObject.close(fd)
def devfs_read(fd: int, buffer: rawptr, size: uint32) -> int:
return DevFSObject.read(fd, buffer, size)
def devfs_write(fd: int, buffer: const rawptr, size: uint32) -> int:
return DevFSObject.write(fd, buffer, size)
def devfs_ioctl(fd: int, cmd: uint32, arg: rawptr) -> int:
return DevFSObject.ioctl(fd, cmd, arg)
def devfs_list_directory(path: const str, buffer: str, size: uint32) -> int:
return DevFSObject.list_directory(path, buffer, size)
serial0_file: devfs_file
def serial0_open(self: rawptr, path: const str, flags: int) -> int:
serial.puts("[serial0] open: ")
serial.puts(path)
serial.puts("\n")
return 0
def serial0_close(self: rawptr, fd: int) -> int:
serial.puts("[serial0] close\n")
return 0
def serial0_read(self: rawptr, fd: int, buffer: rawptr, size: uint32) -> int:
serial.puts("[serial0] read\n")
return 0
def serial0_write(self: rawptr, fd: int, buffer: const rawptr, size: uint32) -> int:
serial.puts("[serial0] write\n")
serial.puts(buffer)
serial.puts("\n")
return size
def devfs_register_serial0() -> int:
global serial0_file
serial0_file = devfs_file()
serial0_file.open = serial0_open
serial0_file.close = serial0_close
serial0_file.read = serial0_read
serial0_file.write = serial0_write
return devfs_create_file("/dev/serial0", serial0_file, None)
virtual class serial1_device(devfs_file):
def open(self, path: const str, flags: int) -> int:
serial.puts("[serial1] open: ")
serial.puts(path)
serial.puts("\n")
return 0
def close(self, fd: int) -> int:
serial.puts("[serial1] close\n")
return 0
def read(self, fd: int, buffer: rawptr, size: uint32) -> int:
serial.puts("[serial1] read\n")
return 0
def write(self, fd: int, buffer: const rawptr, size: uint32) -> int:
serial.puts("[serial1] write\n")
serial.puts(str(buffer))
serial.puts("\n")
return size
serial1_file: serial1_device
def devfs_register_serial1() -> int:
global serial1_file
serial1_file = serial1_device()
return devfs_create_file("/dev/serial1", serial1_file, None)
import drivers.input.keyboard.keyboard as keyboard
import drivers.input.mouse.mouse as mouse
virtual class keyboard_device(devfs_file):
def open(self, path: const str, flags: int) -> int:
return 0
def close(self, fd: int) -> int:
return 0
def read(self, fd: int, buffer: rawptr, size: uint32) -> int:
count: uint32 = 0
while count < size and keyboard.has_data():
sc: uint8 = keyboard.read_scancode()
ch: char = keyboard.scancode_to_ascii(sc)
if ch != '\0':
char*(buffer)[count] = ch
count += 1
return count
def write(self, fd: int, buffer: const rawptr, size: uint32) -> int:
return -1
def ioctl(self, fd: int, request: int, arg: rawptr) -> int:
return 0
kbd_file: keyboard_device
def devfs_register_keyboard() -> int:
global kbd_file
kbd_file = keyboard_device()
keyboard.init()
return devfs_create_file("/dev/input/keyboard", kbd_file, None)
virtual class mouse_device(devfs_file):
def open(self, path: const str, flags: int) -> int:
return 0
def close(self, fd: int) -> int:
return 0
def read(self, fd: int, buffer: rawptr, size: uint32) -> int:
if not mouse.has_data(): return 0
pkt: mouse.mouse_packet
mouse.read_packet(&pkt)
if size >= 1:
uint8*(buffer)[0] = pkt.buttons
if size >= 9:
buf: uint32* = uint32*(uint64(buffer) + 1)
int32*(buf)[0] = mouse.get_x()
int32*(buf)[1] = mouse.get_y()
return 9
return 1
def write(self, fd: int, buffer: const rawptr, size: uint32) -> int:
return -1
def ioctl(self, fd: int, request: int, arg: rawptr) -> int:
return 0
mse_file: mouse_device
def devfs_register_mouse() -> int:
global mse_file
mse_file = mouse_device()
mouse.init()
return devfs_create_file("/dev/input/mouse", mse_file, None)