screen.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #include "screen.h"
  2. #include "../kernel/ports.h"
  3. #include "../kernel/util.h"
  4. int get_screen_offset(int col, int row) {
  5. return (row * MAX_COLS + col) * 2;
  6. }
  7. int get_cursor() {
  8. /*
  9. * screens use their control register as an index to
  10. * select their internal registers of which:
  11. * - 14: high byte of the cursor's offset
  12. * - 15: low byte of the cursor's offset
  13. */
  14. port_byte_out(REG_SCREEN_CTRL, 14);
  15. /* get the high byte and shift it a byte */
  16. int offset = port_byte_in(REG_SCREEN_DATA) << 8;
  17. port_byte_out(REG_SCREEN_CTRL, 15);
  18. /* now add the low byte with the free space from before */
  19. offset += port_byte_in(REG_SCREEN_DATA);
  20. /* remember: each cell is two bytes, not one */
  21. return offset * 2;
  22. }
  23. void set_cursor(int offset) {
  24. /* convert from cell offset to char offset */
  25. offset /= 2;
  26. port_byte_out(REG_SCREEN_CTRL, 14);
  27. port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8));
  28. port_byte_out(REG_SCREEN_CTRL, 15);
  29. port_byte_out(REG_SCREEN_DATA, (unsigned char)offset);
  30. }
  31. int handle_scrolling(int cursor_offset) {
  32. /* if within the screen then don't modify */
  33. if(cursor_offset < MAX_ROWS * MAX_COLS * 2)
  34. return cursor_offset;
  35. /* translate rows back by one */
  36. unsigned int i;
  37. for(i = 1; i < MAX_ROWS; ++i)
  38. {
  39. memory_copy((char*)get_screen_offset(0, i) + VIDEO_ADDRESS,
  40. (char*)get_screen_offset(0, i - 1) + VIDEO_ADDRESS,
  41. MAX_COLS * 2);
  42. }
  43. /* set last line to blank */
  44. char *last_line = (char*)get_screen_offset(0, MAX_ROWS - 1) + VIDEO_ADDRESS;
  45. for(i = 0; i < MAX_COLS * 2; ++i)
  46. last_line[i] = 0;
  47. /*
  48. * move the cursor offset to the last row instead of
  49. * off the screen
  50. */
  51. cursor_offset -= MAX_COLS * 2;
  52. /* updated cursor position */
  53. return cursor_offset;
  54. }
  55. void print_char(char c, int col, int row, char attr_byte) {
  56. unsigned char *vidmem = (unsigned char*) VIDEO_ADDRESS;
  57. if(!attr_byte)
  58. attr_byte = WHITE_ON_BLACK;
  59. /* get the offset of the screen location specified */
  60. int offset;
  61. /*
  62. * if row & col are non-negative then they can be used
  63. * as an offset
  64. */
  65. if(col >= 0 && row >= 0)
  66. offset = get_screen_offset(col, row);
  67. /* otherwise use the cursor's current location */
  68. else
  69. offset = get_cursor();
  70. /* handle a newline */
  71. if(c == '\n')
  72. {
  73. int rows = offset / (2 * MAX_COLS);
  74. offset = get_screen_offset(79,rows);
  75. }
  76. /* else set the character */
  77. else
  78. {
  79. vidmem[offset] = c;
  80. vidmem[offset + 1] = attr_byte;
  81. }
  82. /* update the offset to the next cell */
  83. offset += 2;
  84. /* set scrolling adjustment */
  85. offset = handle_scrolling(offset);
  86. /* update the cursor position */
  87. set_cursor(offset);
  88. }
  89. void print_at(const char *msg, int col, int row) {
  90. if(col >= 0 && row >= 0)
  91. set_cursor(get_screen_offset(col, row));
  92. int i;
  93. for(i = 0; msg[i] != 0; ++i)
  94. print_char(msg[i], col, row, WHITE_ON_BLACK);
  95. }
  96. void print(const char *msg) {
  97. print_at(msg, -1, -1);
  98. }
  99. void clear_screen() {
  100. int row, col;
  101. for(row = 0; row < MAX_ROWS; ++row)
  102. {
  103. for(col = 0; col < MAX_COLS; ++col)
  104. {
  105. print_char(' ', col, row, WHITE_ON_BLACK);
  106. }
  107. }
  108. set_cursor(get_screen_offset(0, 0));
  109. }