ps2_keyboard.c 5.7 KB

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