mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-22 23:43:24 +00:00
完成中断管理模块重构 (#554)
- 支持中断共享 - 把现有驱动程序移植到新的irq模块 - 使用`ProcessorId`标识处理器id - 尚未实现threaded_irq 性能上,edge irq flow handler里面,对于锁的使用,可能有点问题。为了获取/修改common data还有其他几个结构体的状态,进行了多次加锁和放锁,导致性能降低。这是接下来需要优化的点。
This commit is contained in:
@ -1,10 +0,0 @@
|
||||
SRC = $(wildcard *.c)
|
||||
OBJ = $(SRC:.c=.o)
|
||||
CFLAGS += -I .
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all: $(OBJ)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
@ -1,24 +1 @@
|
||||
use crate::init::initcall::INITCALL_LATE;
|
||||
use core::ffi::c_void;
|
||||
use system_error::SystemError;
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
pub mod ps2_keyboard;
|
||||
// pub mod ps2_keyboard_inode;
|
||||
|
||||
extern "C" {
|
||||
fn ps2_keyboard_init() -> c_void;
|
||||
}
|
||||
|
||||
/// 初始化ps2键盘
|
||||
///
|
||||
/// todo: 将ps2键盘适配到设备驱动模型后,把初始化时机改为INITCALL_DEVICE
|
||||
///
|
||||
/// 当前是LATE的原因是键盘驱动的TypeOneFSM需要在tty设备初始化之后才能工作。
|
||||
#[unified_init(INITCALL_LATE)]
|
||||
fn rs_ps2_keyboard_init() -> Result<(), SystemError> {
|
||||
unsafe {
|
||||
ps2_keyboard_init();
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -1,209 +0,0 @@
|
||||
#include "ps2_keyboard.h"
|
||||
#include <arch/x86_64/driver/apic/apic.h>
|
||||
#include <mm/mm.h>
|
||||
#include <mm/slab.h>
|
||||
#include <common/printk.h>
|
||||
#include <filesystem/vfs/VFS.h>
|
||||
#include <common/spinlock.h>
|
||||
#include <common/kfifo.h>
|
||||
|
||||
// 键盘输入缓冲区
|
||||
static struct kfifo_t kb_buf;
|
||||
|
||||
extern void ps2_keyboard_register(struct vfs_file_operations_t *);
|
||||
extern void ps2_keyboard_parse_keycode(uint8_t input);
|
||||
|
||||
// 缓冲区读写锁
|
||||
static spinlock_t ps2_kb_buf_rw_lock;
|
||||
|
||||
/**
|
||||
* @brief 重置ps2键盘输入缓冲区
|
||||
*
|
||||
* @param kbp 缓冲区对象指针
|
||||
*/
|
||||
static void ps2_keyboard_reset_buffer(struct kfifo_t *kbp)
|
||||
{
|
||||
kfifo_reset(kbp);
|
||||
}
|
||||
struct apic_IO_APIC_RTE_entry entry;
|
||||
|
||||
hardware_intr_controller ps2_keyboard_intr_controller =
|
||||
{
|
||||
.enable = apic_ioapic_enable,
|
||||
.disable = apic_ioapic_disable,
|
||||
.install = apic_ioapic_install,
|
||||
.uninstall = apic_ioapic_uninstall,
|
||||
.ack = apic_ioapic_edge_ack,
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 打开键盘文件
|
||||
*
|
||||
* @param inode 所在的inode
|
||||
* @param filp 文件指针
|
||||
* @return long
|
||||
*/
|
||||
long ps2_keyboard_open(void *inode, void *filp)
|
||||
{
|
||||
ps2_keyboard_reset_buffer(&kb_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 关闭键盘文件
|
||||
*
|
||||
* @param inode 所在的inode
|
||||
* @param filp 文件指针
|
||||
* @return long
|
||||
*/
|
||||
long ps2_keyboard_close(void *inode, void *filp)
|
||||
{
|
||||
ps2_keyboard_reset_buffer(&kb_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 键盘io控制接口
|
||||
*
|
||||
* @param inode 所在的inode
|
||||
* @param filp 键盘文件指针
|
||||
* @param cmd 命令
|
||||
* @param arg 参数
|
||||
* @return long
|
||||
*/
|
||||
long ps2_keyboard_ioctl(void *inode, void *filp, uint64_t cmd, uint64_t arg)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case KEYBOARD_CMD_RESET_BUFFER:
|
||||
ps2_keyboard_reset_buffer(&kb_buf);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取键盘文件的操作接口
|
||||
*
|
||||
* @param filp 文件指针
|
||||
* @param buf 输出缓冲区
|
||||
* @param count 要读取的字节数
|
||||
* @param position 读取的位置
|
||||
* @return long 读取的字节数
|
||||
*/
|
||||
long ps2_keyboard_read(void *filp, char *buf, int64_t count, long *position)
|
||||
{
|
||||
// 缓冲区为空则等待
|
||||
while (kfifo_empty(&kb_buf))
|
||||
;
|
||||
|
||||
count = (count > kb_buf.size) ? kb_buf.size : count;
|
||||
return kfifo_out(&kb_buf, buf, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 键盘文件写入接口(无作用,空)
|
||||
*
|
||||
* @param filp
|
||||
* @param buf
|
||||
* @param count
|
||||
* @param position
|
||||
* @return long
|
||||
*/
|
||||
long ps2_keyboard_write(void *filp, char *buf, int64_t count, long *position)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @brief ps2键盘驱动的虚拟文件接口
|
||||
*
|
||||
*/
|
||||
struct vfs_file_operations_t ps2_keyboard_fops =
|
||||
{
|
||||
.open = ps2_keyboard_open,
|
||||
.close = ps2_keyboard_close,
|
||||
.ioctl = ps2_keyboard_ioctl,
|
||||
.read = ps2_keyboard_read,
|
||||
.write = ps2_keyboard_write,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 键盘中断处理函数(中断上半部)
|
||||
* 将数据存入缓冲区
|
||||
* @param irq_num 中断向量号
|
||||
* @param param 参数
|
||||
* @param regs 寄存器信息
|
||||
*/
|
||||
void ps2_keyboard_handler(ul irq_num, ul buf_vaddr, struct pt_regs *regs)
|
||||
{
|
||||
unsigned char x = io_in8(PORT_PS2_KEYBOARD_DATA);
|
||||
ps2_keyboard_parse_keycode((uint8_t)x);
|
||||
}
|
||||
/**
|
||||
* @brief 初始化键盘驱动程序的函数
|
||||
*
|
||||
*/
|
||||
void ps2_keyboard_init()
|
||||
{
|
||||
|
||||
// ======= 初始化键盘循环队列缓冲区 ===========
|
||||
|
||||
// 初始化键盘循环队列缓冲区
|
||||
kfifo_alloc(&kb_buf, ps2_keyboard_buffer_size, 0);
|
||||
|
||||
// ======== 初始化中断RTE entry ==========
|
||||
|
||||
entry.vector = PS2_KEYBOARD_INTR_VECTOR; // 设置中断向量号
|
||||
entry.deliver_mode = IO_APIC_FIXED; // 投递模式:混合
|
||||
entry.dest_mode = DEST_PHYSICAL; // 物理模式投递中断
|
||||
entry.deliver_status = IDLE;
|
||||
entry.trigger_mode = EDGE_TRIGGER; // 设置边沿触发
|
||||
entry.polarity = POLARITY_HIGH; // 高电平触发
|
||||
entry.remote_IRR = IRR_RESET;
|
||||
entry.mask = MASKED;
|
||||
entry.reserved = 0;
|
||||
|
||||
entry.destination.physical.reserved1 = 0;
|
||||
entry.destination.physical.reserved2 = 0;
|
||||
entry.destination.physical.phy_dest = 0; // 设置投递到BSP处理器
|
||||
|
||||
// ======== 初始化键盘控制器,写入配置值 =========
|
||||
wait_ps2_keyboard_write();
|
||||
io_out8(PORT_PS2_KEYBOARD_CONTROL, PS2_KEYBOARD_COMMAND_WRITE);
|
||||
wait_ps2_keyboard_write();
|
||||
io_out8(PORT_PS2_KEYBOARD_DATA, PS2_KEYBOARD_PARAM_INIT);
|
||||
wait_ps2_keyboard_write();
|
||||
|
||||
// 执行一百万次nop,等待键盘控制器把命令执行完毕
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
for (int j = 0; j < 1000; ++j)
|
||||
nop();
|
||||
|
||||
|
||||
// 初始化键盘缓冲区的读写锁
|
||||
spin_init(&ps2_kb_buf_rw_lock);
|
||||
|
||||
// 注册中断处理程序
|
||||
irq_register(PS2_KEYBOARD_INTR_VECTOR, &entry, &ps2_keyboard_handler, (ul)&kb_buf, &ps2_keyboard_intr_controller, "ps/2 keyboard");
|
||||
|
||||
// 先读一下键盘的数据,防止由于在键盘初始化之前,由于按键被按下从而导致接收不到中断。
|
||||
io_in8(PORT_PS2_KEYBOARD_DATA);
|
||||
// 将设备挂载到devfs
|
||||
ps2_keyboard_register(&ps2_keyboard_fops);
|
||||
|
||||
kinfo("ps/2 keyboard registered.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 键盘驱动卸载函数
|
||||
*
|
||||
*/
|
||||
void ps2_keyboard_exit()
|
||||
{
|
||||
irq_unregister(PS2_KEYBOARD_INTR_VECTOR);
|
||||
kfifo_free_alloc(&kb_buf);
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/glib.h>
|
||||
|
||||
#define PS2_KEYBOARD_INTR_VECTOR 0x21 // 键盘的中断向量号
|
||||
|
||||
// 定义键盘循环队列缓冲区大小为100bytes
|
||||
#define ps2_keyboard_buffer_size 8
|
||||
|
||||
#define KEYBOARD_CMD_RESET_BUFFER 1
|
||||
|
||||
#define PORT_PS2_KEYBOARD_DATA 0x60
|
||||
#define PORT_PS2_KEYBOARD_STATUS 0x64
|
||||
#define PORT_PS2_KEYBOARD_CONTROL 0x64
|
||||
|
||||
#define PS2_KEYBOARD_COMMAND_WRITE 0x60 // 向键盘发送配置命令
|
||||
#define PS2_KEYBOARD_COMMAND_READ 0x20 // 读取键盘的配置值
|
||||
#define PS2_KEYBOARD_PARAM_INIT 0x47 // 初始化键盘控制器的配置值
|
||||
|
||||
// ========= 检测键盘控制器输入/输出缓冲区是否已满
|
||||
#define PS2_KEYBOARD_FLAG_OUTBUF_FULL 0x01 // 键盘的输出缓冲区已满标志位
|
||||
#define PS2_KEYBOARD_FLAG_INBUF_FULL 0x02 // 键盘的输入缓冲区已满标志位
|
||||
|
||||
// 等待向键盘控制器写入信息完成
|
||||
// todo: bugfix:在不包含ps2键盘控制器的机器上,这里会卡死
|
||||
#define wait_ps2_keyboard_write() \
|
||||
while (io_in8(PORT_PS2_KEYBOARD_STATUS) & PS2_KEYBOARD_FLAG_INBUF_FULL)
|
||||
// #define wait_ps2_keyboard_write() (1)
|
||||
// 等待从键盘控制器读取信息完成
|
||||
#define wait_ps2_keyboard_read() \
|
||||
while (io_in8(PORT_PS2_KEYBOARD_STATUS) & PS2_KEYBOARD_FLAG_OUTBUF_FULL)
|
||||
// #define wait_ps2_keyboard_read() (1)
|
||||
|
||||
extern struct vfs_file_operations_t ps2_keyboard_fops;
|
||||
|
||||
/**
|
||||
* @brief 键盘驱动卸载函数
|
||||
*
|
||||
*/
|
||||
void ps2_keyboard_exit();
|
@ -1,9 +1,24 @@
|
||||
use core::{ffi::c_void, sync::atomic::AtomicI32};
|
||||
use core::hint::spin_loop;
|
||||
|
||||
use alloc::sync::{Arc, Weak};
|
||||
use alloc::{
|
||||
string::ToString,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
use crate::{
|
||||
driver::base::device::device_number::{DeviceNumber, Major},
|
||||
arch::{io::PortIOArch, CurrentPortIOArch},
|
||||
driver::{
|
||||
base::device::device_number::{DeviceNumber, Major},
|
||||
input::ps2_dev::Ps2StatusRegister,
|
||||
},
|
||||
exception::{
|
||||
irqdata::IrqHandlerData,
|
||||
irqdesc::{IrqHandleFlags, IrqHandler, IrqReturn},
|
||||
manage::irq_manager,
|
||||
IrqNumber,
|
||||
},
|
||||
filesystem::{
|
||||
devfs::{devfs_register, DevFS, DeviceINode},
|
||||
vfs::{
|
||||
@ -11,13 +26,30 @@ use crate::{
|
||||
FileSystem, FileType, IndexNode, Metadata,
|
||||
},
|
||||
},
|
||||
include::bindings::bindings::vfs_file_operations_t,
|
||||
init::initcall::INITCALL_DEVICE,
|
||||
libs::{keyboard_parser::TypeOneFSM, rwlock::RwLock, spinlock::SpinLock},
|
||||
time::TimeSpec,
|
||||
};
|
||||
use system_error::SystemError;
|
||||
|
||||
/// PS2键盘的中断向量号
|
||||
const PS2_KEYBOARD_INTR_VECTOR: IrqNumber = IrqNumber::new(0x21);
|
||||
|
||||
const PORT_PS2_KEYBOARD_DATA: u8 = 0x60;
|
||||
const PORT_PS2_KEYBOARD_STATUS: u8 = 0x64;
|
||||
const PORT_PS2_KEYBOARD_CONTROL: u8 = 0x64;
|
||||
|
||||
/// 向键盘发送配置命令
|
||||
const PS2_KEYBOARD_COMMAND_WRITE: u8 = 0x60;
|
||||
|
||||
/// 读取键盘的配置值
|
||||
#[allow(dead_code)]
|
||||
const PS2_KEYBOARD_COMMAND_READ: u8 = 0x20;
|
||||
/// 初始化键盘控制器的配置值
|
||||
const PS2_KEYBOARD_PARAM_INIT: u8 = 0x47;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LockedPS2KeyBoardInode(RwLock<PS2KeyBoardInode>, AtomicI32); // self.1 用来记录有多少个文件打开了这个inode
|
||||
pub struct LockedPS2KeyBoardInode(RwLock<PS2KeyBoardInode>);
|
||||
|
||||
lazy_static! {
|
||||
static ref PS2_KEYBOARD_FSM: SpinLock<TypeOneFSM> = SpinLock::new(TypeOneFSM::new());
|
||||
@ -33,17 +65,14 @@ pub struct PS2KeyBoardInode {
|
||||
fs: Weak<DevFS>,
|
||||
/// INode 元数据
|
||||
metadata: Metadata,
|
||||
/// 键盘操作函数
|
||||
f_ops: vfs_file_operations_t,
|
||||
}
|
||||
|
||||
impl LockedPS2KeyBoardInode {
|
||||
pub fn new(f_ops: &vfs_file_operations_t) -> Arc<Self> {
|
||||
pub fn new() -> Arc<Self> {
|
||||
let inode = PS2KeyBoardInode {
|
||||
// uuid: Uuid::new_v5(),
|
||||
self_ref: Weak::default(),
|
||||
fs: Weak::default(),
|
||||
f_ops: f_ops.clone(), // 从引用复制一遍获取所有权
|
||||
metadata: Metadata {
|
||||
dev_id: 1,
|
||||
inode_id: generate_inode_id(),
|
||||
@ -62,10 +91,7 @@ impl LockedPS2KeyBoardInode {
|
||||
},
|
||||
};
|
||||
|
||||
let result = Arc::new(LockedPS2KeyBoardInode(
|
||||
RwLock::new(inode),
|
||||
AtomicI32::new(0),
|
||||
));
|
||||
let result = Arc::new(LockedPS2KeyBoardInode(RwLock::new(inode)));
|
||||
result.0.write().self_ref = Arc::downgrade(&result);
|
||||
|
||||
return result;
|
||||
@ -78,9 +104,8 @@ impl DeviceINode for LockedPS2KeyBoardInode {
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle] // 不重命名
|
||||
pub extern "C" fn ps2_keyboard_register(f_ops: &vfs_file_operations_t) {
|
||||
devfs_register("ps2_keyboard", LockedPS2KeyBoardInode::new(f_ops))
|
||||
fn ps2_keyboard_register() {
|
||||
devfs_register("ps2_keyboard", LockedPS2KeyBoardInode::new())
|
||||
.expect("Failed to register ps/2 keyboard");
|
||||
}
|
||||
|
||||
@ -88,21 +113,11 @@ impl IndexNode for LockedPS2KeyBoardInode {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
len: usize,
|
||||
buf: &mut [u8],
|
||||
_len: usize,
|
||||
_buf: &mut [u8],
|
||||
_data: &mut FilePrivateData,
|
||||
) -> Result<usize, SystemError> {
|
||||
let guard = self.0.read();
|
||||
let func = guard.f_ops.read.unwrap();
|
||||
let r = unsafe {
|
||||
func(
|
||||
0 as *mut c_void,
|
||||
&mut buf[0..len] as *mut [u8] as *mut i8,
|
||||
len as i64,
|
||||
0 as *mut i64,
|
||||
)
|
||||
};
|
||||
return Ok(r as usize);
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
@ -112,28 +127,14 @@ impl IndexNode for LockedPS2KeyBoardInode {
|
||||
_buf: &[u8],
|
||||
_data: &mut FilePrivateData,
|
||||
) -> Result<usize, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
||||
fn open(&self, _data: &mut FilePrivateData, _mode: &FileMode) -> Result<(), SystemError> {
|
||||
let prev_ref_count = self.1.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
|
||||
if prev_ref_count == 0 {
|
||||
// 第一次打开,需要初始化
|
||||
let guard = self.0.write();
|
||||
let func = guard.f_ops.open.unwrap();
|
||||
let _ = unsafe { func(0 as *mut c_void, 0 as *mut c_void) };
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError> {
|
||||
let prev_ref_count = self.1.fetch_sub(1, core::sync::atomic::Ordering::SeqCst);
|
||||
if prev_ref_count == 1 {
|
||||
// 最后一次关闭,需要释放
|
||||
let guard = self.0.write();
|
||||
let func = guard.f_ops.close.unwrap();
|
||||
let _ = unsafe { func(0 as *mut c_void, 0 as *mut c_void) };
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -166,9 +167,85 @@ impl IndexNode for LockedPS2KeyBoardInode {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[no_mangle]
|
||||
/// for test
|
||||
pub extern "C" fn ps2_keyboard_parse_keycode(input: u8) {
|
||||
PS2_KEYBOARD_FSM.lock().parse(input);
|
||||
#[derive(Debug)]
|
||||
struct Ps2KeyboardIrqHandler;
|
||||
|
||||
impl IrqHandler for Ps2KeyboardIrqHandler {
|
||||
fn handle(
|
||||
&self,
|
||||
_irq: IrqNumber,
|
||||
_static_data: Option<&dyn IrqHandlerData>,
|
||||
_dev_id: Option<Arc<dyn IrqHandlerData>>,
|
||||
) -> Result<IrqReturn, SystemError> {
|
||||
// 先检查状态寄存器,看看是否有数据
|
||||
let status = unsafe { CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_STATUS.into()) };
|
||||
let status = Ps2StatusRegister::from(status);
|
||||
if !status.outbuf_full() {
|
||||
return Ok(IrqReturn::NotHandled);
|
||||
}
|
||||
|
||||
let input = unsafe { CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_DATA.into()) };
|
||||
// wait_ps2_keyboard_read();
|
||||
PS2_KEYBOARD_FSM.lock().parse(input);
|
||||
|
||||
return Ok(IrqReturn::Handled);
|
||||
}
|
||||
}
|
||||
|
||||
impl Ps2KeyboardIrqHandler {
|
||||
const INTR_HANDLE_FLAGS: IrqHandleFlags =
|
||||
IrqHandleFlags::from_bits_truncate(IrqHandleFlags::IRQF_TRIGGER_RISING.bits());
|
||||
}
|
||||
|
||||
/// 等待 PS/2 键盘的输入缓冲区为空
|
||||
fn wait_ps2_keyboard_write() {
|
||||
let mut status: Ps2StatusRegister;
|
||||
loop {
|
||||
status = Ps2StatusRegister::from(unsafe {
|
||||
CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_STATUS.into())
|
||||
});
|
||||
if !status.inbuf_full() {
|
||||
break;
|
||||
}
|
||||
|
||||
spin_loop();
|
||||
}
|
||||
}
|
||||
#[unified_init(INITCALL_DEVICE)]
|
||||
fn ps2_keyboard_init() -> Result<(), SystemError> {
|
||||
// ======== 初始化键盘控制器,写入配置值 =========
|
||||
wait_ps2_keyboard_write();
|
||||
unsafe {
|
||||
CurrentPortIOArch::out8(PORT_PS2_KEYBOARD_CONTROL.into(), PS2_KEYBOARD_COMMAND_WRITE);
|
||||
wait_ps2_keyboard_write();
|
||||
CurrentPortIOArch::out8(PORT_PS2_KEYBOARD_DATA.into(), PS2_KEYBOARD_PARAM_INIT);
|
||||
wait_ps2_keyboard_write();
|
||||
}
|
||||
|
||||
// 执行一百万次nop,等待键盘控制器把命令执行完毕
|
||||
for _ in 0..1000000 {
|
||||
spin_loop();
|
||||
}
|
||||
|
||||
irq_manager()
|
||||
.request_irq(
|
||||
PS2_KEYBOARD_INTR_VECTOR,
|
||||
"ps2keyboard".to_string(),
|
||||
&Ps2KeyboardIrqHandler,
|
||||
Ps2KeyboardIrqHandler::INTR_HANDLE_FLAGS,
|
||||
None,
|
||||
)
|
||||
.expect("Failed to request irq for ps2 keyboard");
|
||||
|
||||
// 先读一下键盘的数据,防止由于在键盘初始化之前,由于按键被按下从而导致接收不到中断。
|
||||
let status = unsafe { CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_STATUS.into()) };
|
||||
let status = Ps2StatusRegister::from(status);
|
||||
if status.outbuf_full() {
|
||||
unsafe { CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_DATA.into()) };
|
||||
}
|
||||
|
||||
// 将设备挂载到devfs
|
||||
ps2_keyboard_register();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Reference in New Issue
Block a user