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)