1 #include "ps2_keyboard.h"
2 #include <driver/interrupt/apic/apic.h>
3 #include <mm/mm.h>
4 #include <mm/slab.h>
5 #include <common/printk.h>
6 #include <filesystem/vfs/VFS.h>
7 #include <common/wait_queue.h>
8 #include <common/spinlock.h>
9 #include <common/kfifo.h>
10 
11 // 键盘输入缓冲区
12 static struct kfifo_t kb_buf;
13 
14 // 缓冲区等待队列
15 static wait_queue_node_t ps2_keyboard_wait_queue;
16 extern void ps2_keyboard_register(struct vfs_file_operations_t *);
17 extern void ps2_keyboard_parse_keycode(uint8_t input);
18 
19 // 缓冲区读写锁
20 static spinlock_t ps2_kb_buf_rw_lock;
21 
22 /**
23  * @brief 重置ps2键盘输入缓冲区
24  *
25  * @param kbp 缓冲区对象指针
26  */
ps2_keyboard_reset_buffer(struct kfifo_t * kbp)27 static void ps2_keyboard_reset_buffer(struct kfifo_t *kbp)
28 {
29     kfifo_reset(kbp);
30 }
31 struct apic_IO_APIC_RTE_entry entry;
32 
33 hardware_intr_controller ps2_keyboard_intr_controller =
34     {
35         .enable = apic_ioapic_enable,
36         .disable = apic_ioapic_disable,
37         .install = apic_ioapic_install,
38         .uninstall = apic_ioapic_uninstall,
39         .ack = apic_ioapic_edge_ack,
40 
41 };
42 
43 /**
44  * @brief 打开键盘文件
45  *
46  * @param inode 所在的inode
47  * @param filp 文件指针
48  * @return long
49  */
ps2_keyboard_open(struct vfs_index_node_t * inode,struct vfs_file_t * filp)50 long ps2_keyboard_open(struct vfs_index_node_t *inode, struct vfs_file_t *filp)
51 {
52     ps2_keyboard_reset_buffer(&kb_buf);
53     return 0;
54 }
55 
56 /**
57  * @brief 关闭键盘文件
58  *
59  * @param inode 所在的inode
60  * @param filp 文件指针
61  * @return long
62  */
ps2_keyboard_close(struct vfs_index_node_t * inode,struct vfs_file_t * filp)63 long ps2_keyboard_close(struct vfs_index_node_t *inode, struct vfs_file_t *filp)
64 {
65     ps2_keyboard_reset_buffer(&kb_buf);
66     return 0;
67 }
68 
69 /**
70  * @brief 键盘io控制接口
71  *
72  * @param inode 所在的inode
73  * @param filp 键盘文件指针
74  * @param cmd 命令
75  * @param arg 参数
76  * @return long
77  */
ps2_keyboard_ioctl(struct vfs_index_node_t * inode,struct vfs_file_t * filp,uint64_t cmd,uint64_t arg)78 long ps2_keyboard_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *filp, uint64_t cmd, uint64_t arg)
79 {
80     switch (cmd)
81     {
82     case KEYBOARD_CMD_RESET_BUFFER:
83         ps2_keyboard_reset_buffer(&kb_buf);
84         break;
85 
86     default:
87         break;
88     }
89     return 0;
90 }
91 
92 /**
93  * @brief 读取键盘文件的操作接口
94  *
95  * @param filp 文件指针
96  * @param buf 输出缓冲区
97  * @param count 要读取的字节数
98  * @param position 读取的位置
99  * @return long 读取的字节数
100  */
ps2_keyboard_read(struct vfs_file_t * filp,char * buf,int64_t count,long * position)101 long ps2_keyboard_read(struct vfs_file_t *filp, char *buf, int64_t count, long *position)
102 {
103     // 缓冲区为空则等待
104     if (kfifo_empty(&kb_buf))
105         wait_queue_sleep_on(&ps2_keyboard_wait_queue);
106 
107     count = (count > kb_buf.size) ? kb_buf.size : count;
108     return kfifo_out(&kb_buf, buf, count);
109 }
110 
111 /**
112  * @brief 键盘文件写入接口(无作用,空)
113  *
114  * @param filp
115  * @param buf
116  * @param count
117  * @param position
118  * @return long
119  */
ps2_keyboard_write(struct vfs_file_t * filp,char * buf,int64_t count,long * position)120 long ps2_keyboard_write(struct vfs_file_t *filp, char *buf, int64_t count, long *position)
121 {
122     return 0;
123 }
124 /**
125  * @brief ps2键盘驱动的虚拟文件接口
126  *
127  */
128 struct vfs_file_operations_t ps2_keyboard_fops =
129     {
130         .open = ps2_keyboard_open,
131         .close = ps2_keyboard_close,
132         .ioctl = ps2_keyboard_ioctl,
133         .read = ps2_keyboard_read,
134         .write = ps2_keyboard_write,
135 };
136 
137 /**
138  * @brief 键盘中断处理函数(中断上半部)
139  *  将数据存入缓冲区
140  * @param irq_num 中断向量号
141  * @param param 参数
142  * @param regs 寄存器信息
143  */
ps2_keyboard_handler(ul irq_num,ul buf_vaddr,struct pt_regs * regs)144 void ps2_keyboard_handler(ul irq_num, ul buf_vaddr, struct pt_regs *regs)
145 {
146     unsigned char x = io_in8(PORT_PS2_KEYBOARD_DATA);
147     ps2_keyboard_parse_keycode((uint8_t)x);
148     uint8_t count = kfifo_in((struct kfifo_t *)buf_vaddr, &x, sizeof(unsigned char));
149     // if (count == 0)
150     // {
151     //     kwarn("ps2 keyboard buffer full.");
152     //     return;
153     // }
154 
155     wait_queue_wakeup(&ps2_keyboard_wait_queue, PROC_UNINTERRUPTIBLE);
156 
157 }
158 /**
159  * @brief 初始化键盘驱动程序的函数
160  *
161  */
ps2_keyboard_init()162 void ps2_keyboard_init()
163 {
164 
165     // ======= 初始化键盘循环队列缓冲区 ===========
166 
167     // 初始化键盘循环队列缓冲区
168     kfifo_alloc(&kb_buf, ps2_keyboard_buffer_size, 0);
169 
170     // ======== 初始化中断RTE entry ==========
171 
172     entry.vector = PS2_KEYBOARD_INTR_VECTOR; // 设置中断向量号
173     entry.deliver_mode = IO_APIC_FIXED;      // 投递模式:混合
174     entry.dest_mode = DEST_PHYSICAL;         // 物理模式投递中断
175     entry.deliver_status = IDLE;
176     entry.trigger_mode = EDGE_TRIGGER; // 设置边沿触发
177     entry.polarity = POLARITY_HIGH;    // 高电平触发
178     entry.remote_IRR = IRR_RESET;
179     entry.mask = MASKED;
180     entry.reserved = 0;
181 
182     entry.destination.physical.reserved1 = 0;
183     entry.destination.physical.reserved2 = 0;
184     entry.destination.physical.phy_dest = 0; // 设置投递到BSP处理器
185 
186     // ======== 初始化键盘控制器,写入配置值 =========
187     wait_ps2_keyboard_write();
188     io_out8(PORT_PS2_KEYBOARD_CONTROL, PS2_KEYBOARD_COMMAND_WRITE);
189     wait_ps2_keyboard_write();
190     io_out8(PORT_PS2_KEYBOARD_DATA, PS2_KEYBOARD_PARAM_INIT);
191     wait_ps2_keyboard_write();
192 
193     // 执行一百万次nop,等待键盘控制器把命令执行完毕
194     for (int i = 0; i < 1000; ++i)
195         for (int j = 0; j < 1000; ++j)
196             nop();
197 
198     wait_queue_init(&ps2_keyboard_wait_queue, NULL);
199     // 初始化键盘缓冲区的读写锁
200     spin_init(&ps2_kb_buf_rw_lock);
201 
202     // 注册中断处理程序
203     irq_register(PS2_KEYBOARD_INTR_VECTOR, &entry, &ps2_keyboard_handler, (ul)&kb_buf, &ps2_keyboard_intr_controller, "ps/2 keyboard");
204 
205     // 先读一下键盘的数据,防止由于在键盘初始化之前,由于按键被按下从而导致接收不到中断。
206     io_in8(PORT_PS2_KEYBOARD_DATA);
207     // 将设备挂载到devfs
208     ps2_keyboard_register(&ps2_keyboard_fops);
209 
210     kinfo("ps/2 keyboard registered.");
211 }
212 
213 /**
214  * @brief 键盘驱动卸载函数
215  *
216  */
ps2_keyboard_exit()217 void ps2_keyboard_exit()
218 {
219     irq_unregister(PS2_KEYBOARD_INTR_VECTOR);
220     kfifo_free_alloc(&kb_buf);
221 
222 }
223