tty.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #include <kernel/event/evtqueue.hpp>
  2. #include <kernel/hw/serial.h>
  3. #include <kernel/process.hpp>
  4. #include <kernel/tty.hpp>
  5. #include <kernel/vga.hpp>
  6. #include <stdint.h>
  7. #include <stdio.h>
  8. #define TTY_DATA (1 << 0)
  9. #define TTY_EOF (1 << 1)
  10. #define TTY_INT (1 << 2)
  11. tty::tty()
  12. : buf(BUFFER_SIZE)
  13. {
  14. }
  15. void tty::print(const char* str)
  16. {
  17. while (*str != '\0')
  18. this->putchar(*(str++));
  19. }
  20. size_t tty::read(char* buf, size_t buf_size, size_t n)
  21. {
  22. size_t orig_n = n;
  23. while (buf_size && n) {
  24. if (this->buf.empty()) {
  25. while (this->blocklist.empty()) {
  26. current_thread->attr.ready = 0;
  27. current_thread->attr.wait = 1;
  28. this->blocklist.subscribe(current_thread);
  29. schedule();
  30. if (!this->blocklist.empty()) {
  31. this->blocklist.unsubscribe(current_thread);
  32. break;
  33. }
  34. }
  35. auto evt = this->blocklist.front();
  36. switch ((int)evt.data1) {
  37. // INTERRUPT
  38. case TTY_INT:
  39. return -1;
  40. // DATA
  41. case TTY_DATA:
  42. break;
  43. // EOF
  44. case TTY_EOF:
  45. return orig_n - n;
  46. }
  47. }
  48. *buf = this->buf.get();
  49. --buf_size;
  50. --n;
  51. if (*(buf++) == '\n')
  52. break;
  53. }
  54. return orig_n - n;
  55. }
  56. vga_tty::vga_tty()
  57. {
  58. snprintf(this->name, sizeof(this->name), "ttyVGA");
  59. }
  60. serial_tty::serial_tty(int id)
  61. : id(id)
  62. {
  63. snprintf(this->name, sizeof(this->name), "ttyS%x", (int)id);
  64. }
  65. void serial_tty::putchar(char c)
  66. {
  67. serial_send_data(id, c);
  68. }
  69. void vga_tty::putchar(char c)
  70. {
  71. static struct vga_char vc = { .c = '\0', .color = VGA_CHAR_COLOR_WHITE };
  72. vc.c = c;
  73. vga_put_char(&vc);
  74. }
  75. void vga_tty::recvchar(char c)
  76. {
  77. // TODO: keyboard scan code
  78. buf.put(c);
  79. }
  80. void serial_tty::recvchar(char c)
  81. {
  82. switch (c) {
  83. case '\r':
  84. buf.put('\n');
  85. if (echo) {
  86. serial_send_data(PORT_SERIAL0, '\r');
  87. serial_send_data(PORT_SERIAL0, '\n');
  88. }
  89. this->blocklist.push(kernel::evt { nullptr, (void*)TTY_DATA, nullptr, nullptr });
  90. this->blocklist.notify();
  91. break;
  92. // ^?: backspace
  93. case 0x7f:
  94. if (!buf.empty() && buf.back() != '\n') {
  95. buf.pop();
  96. if (echo) {
  97. serial_send_data(PORT_SERIAL0, 0x08);
  98. serial_send_data(PORT_SERIAL0, '\x1b');
  99. serial_send_data(PORT_SERIAL0, '[');
  100. serial_send_data(PORT_SERIAL0, 'K');
  101. }
  102. }
  103. break;
  104. // ^U: clear the line
  105. case 0x15:
  106. while (!buf.empty() && buf.back() != '\n') {
  107. buf.pop();
  108. if (echo) {
  109. // clear the line
  110. // serial_send_data(PORT_SERIAL0, '\r');
  111. // serial_send_data(PORT_SERIAL0, '\x1b');
  112. // serial_send_data(PORT_SERIAL0, '[');
  113. // serial_send_data(PORT_SERIAL0, '2');
  114. // serial_send_data(PORT_SERIAL0, 'K');
  115. serial_send_data(PORT_SERIAL0, 0x08);
  116. serial_send_data(PORT_SERIAL0, '\x1b');
  117. serial_send_data(PORT_SERIAL0, '[');
  118. serial_send_data(PORT_SERIAL0, 'K');
  119. }
  120. }
  121. break;
  122. // ^C: SIGINT
  123. case 0x03:
  124. this->blocklist.push(kernel::evt { nullptr, (void*)TTY_INT, nullptr, nullptr });
  125. this->blocklist.notify();
  126. procs->send_signal_grp(fg_pgroup, kernel::SIGINT);
  127. break;
  128. // ^D: EOF
  129. case 0x04:
  130. this->blocklist.push(kernel::evt { nullptr, (void*)TTY_EOF, nullptr, nullptr });
  131. this->blocklist.notify();
  132. break;
  133. // ^Z: SIGSTOP
  134. case 0x1a:
  135. this->blocklist.push(kernel::evt { nullptr, (void*)TTY_INT, nullptr, nullptr });
  136. this->blocklist.notify();
  137. procs->send_signal_grp(fg_pgroup, kernel::SIGSTOP);
  138. break;
  139. // ^\: SIGQUIT
  140. case 0x1c:
  141. this->blocklist.push(kernel::evt { nullptr, (void*)TTY_INT, nullptr, nullptr });
  142. this->blocklist.notify();
  143. procs->send_signal_grp(fg_pgroup, kernel::SIGQUIT);
  144. break;
  145. default:
  146. buf.put(c);
  147. if (echo)
  148. serial_send_data(PORT_SERIAL0, c);
  149. break;
  150. }
  151. }