news 2026/8/18 17:11:58

手写Zeal 8-bit OS设备驱动:从0到1实现键盘与串口驱动的完整教程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手写Zeal 8-bit OS设备驱动:从0到1实现键盘与串口驱动的完整教程

手写Zeal 8-bit OS设备驱动:从0到1实现键盘与串口驱动的完整教程

【免费下载链接】Zeal-8-bit-OSAn Operating System for Z80 computers, written in assembly项目地址: https://gitcode.com/gh_mirrors/ze/Zeal-8-bit-OS

Zeal 8-bit OS 是一款专为 Z80 计算机设计的开源操作系统,整个内核用汇编语言编写,而设备驱动体系正是理解它内部运作的最佳入口。本教程面向新手,不要求你熟悉汇编细节,只需跟随步骤,即可完成键盘驱动串口驱动从注册到调用的完整开发流程,真正搞懂 Zeal 8-bit OS 设备驱动的工作方式。

什么是 Zeal 8-bit OS 设备驱动?先看驱动结构

在 Zeal 8-bit OS 中,一个驱动程序本质上是一张函数指针表:4 字节的名字 + 8 个函数地址。内核通过这张表统一调用硬件,用户程序则通过 VFS 层访问驱动,完全不需要关心底层细节。

驱动必须实现的 8 个函数分别是:

函数作用
init开机时初始化硬件,返回 0 表示成功
read从设备读取数据
write向设备写入数据
open/close打开 / 关闭设备
seek移动读写位置
ioctl设置设备参数(波特率、输入模式等)
deinit卸载驱动时清理资源

驱动名最长 4 个字符,例如SER0(串口)、KBD0(键盘),要求全部是字母数字。驱动结构体的完整定义在 drivers_h.asm 中,官方驱动文档见 drivers.md。

驱动注册的两步走:放对位置 + 返回状态码

注册驱动非常简单:把上面这张结构体放进名为DRV_VECTORS的 section 即可。开机时,内核的驱动管理器会遍历整个 section,逐个调用init函数:

SECTION DRV_VECTORS DEFB "SER0" ; 驱动名 DEFW uart_init ; init DEFW uart_read ; read DEFW uart_write ; write DEFW uart_open ; open DEFW uart_close ; close DEFW uart_seek ; seek DEFW uart_ioctl ; ioctl DEFW uart_deinit ; deinit

这里有个关键约定:如果驱动 A 依赖驱动 B,B 的结构体必须放在 A 前面,因为依赖关系在编译期就要解析完毕。这个遍历与注册逻辑实现在 drivers.asm 的zos_drivers_init中。

init的返回值决定驱动的最终命运:

  • 返回ERR_SUCCESS(0):驱动注册成功,用户程序可以 open/read/write
  • 返回ERR_DRIVER_HIDDEN:驱动注册但对外隐藏,常用于只给文件系统用的磁盘驱动
  • 返回其他错误码:注册失败,跳过该驱动

准备工作:获取源码与目录速览

动手前先克隆仓库:

git clone https://gitcode.com/gh_mirrors/ze/Zeal-8-bit-OS

项目里与驱动开发最相关的目录:

  • kernel/:内核本体,drivers.asm是驱动管理器
  • target/zeal8bit/:Zeal 8-bit 目标机的硬件驱动,keyboard.asmuart.asm是我们的学习样板
  • include/drivers/:驱动接口头文件,如keyboard_h.asmvideo_text_h.asm
  • kernel_headers/sdcc/include/:C 语言驱动接口头文件(zos_keyboard.hzos_serial.h

实现键盘驱动:从裸按键到带缓冲的输入

键盘驱动位于target/zeal8bit/keyboard.asm,它的核心职责是:读取按键 → 处理 → 存入 FIFO 缓冲区 → 供用户程序 read。

第一步:init 中注册为标准输入

keyboard_init只做三件事:初始化底层键盘实现(PS/2 或并口)、清空 FIFO、调用zos_vfs_set_stdin把自己注册为系统默认标准输入。这样 shell 和所有程序都能直接读取键盘,无需关心具体硬件。

第二步:用 ioctl 实现三种输入模式

键盘驱动对外只提供一个 ioctl 命令KB_CMD_SET_MODE,用于切换输入模式,定义见 keyboard_h.asm:

  • RAW 模式:不做任何处理,按下/松开原样上报。比如按下左 Shift 再按 A,程序收到0x93(左 Shift)和0x61(小写 a)
  • COOKED 模式(默认):按键先经过处理再存入缓冲区,支持大小写、方向键、退格、Tab 等,遇到回车才刷新
  • HALFCOOKED 模式:介于两者之间,遇到不支持的键会填入缓冲区并返回ERR_SPECIAL_STATE

另外还有阻塞/非阻塞读取标志。C 语言下可通过 zos_keyboard.h 直接使用这些常量,例如设置原始模式:

ioctl(fd, KB_CMD_SET_MODE, KB_MODE_RAW | KB_READ_NON_BLOCK);

第三步:read 返回按键码

在 RAW 模式下,read 返回的是按键码:普通字符直接是 ASCII(如'a'= 0x61),特殊键使用 0x80~0xFC 的扩展码(如KB_LEFT_SHIFT= 0x93)。松开按键时,前面会带一个KB_RELEASED(0xFE)前缀:

0x61 [...] 0xFE 0x61 A ... A 已松开

实现串口驱动:UART 驱动的完整骨架

串口驱动target/zeal8bit/uart.asm是另一个经典范例,它的init除了初始化波特率外,还承担一个重要任务:当系统配置了"UART 作为标准输出"时,调用zos_vfs_set_stdout把自己挂到 stdout 上,并发送 ANSI 转义序列清屏、设置光标。也就是说,串口驱动可以同时扮演显示驱动,非常适合没有屏幕的裸机调试场景。

串口的 ioctl 命令与键盘完全不同,定义在 zos_serial.h,包括:

  • SERIAL_CMD_SET_ATTR/SERIAL_CMD_GET_ATTR:设置/读取属性(如 RAW 模式)
  • SERIAL_CMD_SET_BAUDRATE/SERIAL_CMD_GET_BAUDRATE:设置/读取波特率
  • SERIAL_SET_TIMEOUT/SERIAL_SET_BLOCKING:超时与阻塞控制

syscall 层如何把参数传递给驱动的 read/write,规则与系统调用表完全一致,可参考 syscalls.md。如果你想写一个自己的串口小工具,romdisk 里的 uart.asm 是现成的用户态参考。

编译测试:让驱动跑起来

Zeal 8-bit OS 使用 Kconfig + Makefile 构建。驱动是否作为标准输入/输出,由目标机配置决定,可在configs/zeal8bit/os.conf等配置文件中调整,例如:

  • 配置CONFIG_TARGET_STDOUT_UART后,串口会自动成为标准输出
  • 键盘默认注册为标准输入,无需额外配置

构建整个系统:

make

烧录到模拟器或真机后,开机日志会打印类似Driver: SER0 init success的信息,这正是zos_drivers_init逐一遍历DRV_VECTORS的成果。之后你在 shell 里输入字符、通过串口收发数据,背后都是我们刚刚拆解的那套驱动机制在运转。

新手常见问题速查

Q:驱动名字冲突了怎么办?内核会返回ERR_ALREADY_EXIST并跳过该驱动,所以命名前先查重,SER0KBD0这类有编号的名字最稳妥。

Q:我的驱动需要独占硬件,不想暴露给用户程序?init返回ERR_DRIVER_HIDDEN即可,驱动仍可用但对外隐藏。

Q:键盘和串口同时注册,会不会抢占?不会。一个通过zos_vfs_set_stdin成为标准输入,一个通过zos_vfs_set_stdout成为标准输出,VFS 层各司其职。

总结:驱动开发其实只有三步

回顾全文,Zeal 8-bit OS 设备驱动开发可以浓缩为三步:

  1. 实现 8 个函数(不用的返回ERR_NOT_SUPPORTED即可)
  2. 把结构体放进DRV_VECTORSsection
  3. init中返回正确的状态码,必要时调用zos_vfs_set_stdin/stdout挂载为标准设备

掌握了键盘驱动与串口驱动这两个样板,你就已经具备了读写 Zeal 8-bit OS 内核驱动代码的能力。下一步不妨尝试阅读 video.asm(显示驱动)或 compactflash.asm(存储驱动),把同样的方法论应用到更多硬件上。祝你在 Z80 的世界里玩得开心!😄

【免费下载链接】Zeal-8-bit-OSAn Operating System for Z80 computers, written in assembly项目地址: https://gitcode.com/gh_mirrors/ze/Zeal-8-bit-OS

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/18 17:08:30

VBrowser-Android架构剖析:DownloadManager任务调度与前台下载服务

VBrowser-Android架构剖析:DownloadManager任务调度与前台下载服务 【免费下载链接】VBrowser-Android 全网视频嗅探缓存APP 项目地址: https://gitcode.com/gh_mirrors/vb/VBrowser-Android VBrowser-Android 是一款开源的全网视频嗅探缓存APP,它…

作者头像 李华
网站建设 2026/8/18 17:03:53

Linux 网络接口命名规则

非常好的问题 👏——eth0、ens33、enp4s0、eno1 这些名字确实让人一开始很困惑,其实它们的区别来自于 Linux 的“可预测网络接口命名规则(Predictable Network Interface Names)” 的演进。下面我系统讲清楚它们的来源、命名逻辑和…

作者头像 李华