#include "type.h" #include "stdio.h" #include "const.h" #include "protect.h" #include "string.h" #include "proc.h" #include "tty.h" #include "console.h" #include "global.h" #include "keyboard.h" #include "proto.h" #include "x86.h" #include "memman.h" #include "assert.h" /***************************************************************************** * Low level vga driver *****************************************************************************/ /***************************************************************************** * Display the cursor by setting CRTC (6845 compatible) registers. * * @param position Position of the cursor based on the beginning of the video * memory. Note that it counts in WORDs, not in BYTEs. *****************************************************************************/ static inline void vga_set_cursor(unsigned int position) { disable_int(); outb(CRTC_ADDR_REG, CURSOR_H); outb(CRTC_DATA_REG, (position >> 8) & 0xFF); outb(CRTC_ADDR_REG, CURSOR_L); outb(CRTC_DATA_REG, position & 0xFF); enable_int(); } static inline void vga_disable_cursor() { outb(CRTC_ADDR_REG, 0x0A); outb(CRTC_DATA_REG, 0x20); } static inline void vga_enable_cursor(u8 cursor_start, u8 cursor_end) { outb(0x3D4, 0x0A); outb(0x3D5, (inb(0x3D5) & 0xC0) | cursor_start); outb(0x3D4, 0x0B); outb(0x3D5, (inb(0x3D5) & 0xE0) | cursor_end); } /***************************************************************************** * Routine for hardware screen scrolling. * * @param addr Offset in the video memory. *****************************************************************************/ static inline void vga_set_video_start_addr(u32 addr) { disable_int(); outb(CRTC_ADDR_REG, START_ADDR_H); outb(CRTC_DATA_REG, (addr >> 8) & 0xFF); outb(CRTC_ADDR_REG, START_ADDR_L); outb(CRTC_DATA_REG, addr & 0xFF); enable_int(); } /***************************************************************************** * Write data directly to Video Memory cell * * @param pos text mode position(pos*2 yourself) * @param dat data to be written, with format [ BG | FG | ASCII ] *****************************************************************************/ static inline void vga_put_raw(u32 pos, u16 dat) { u16* pch = (u16*)K_PHY2LIN(V_MEM_BASE + pos); *pch = dat; } /***************************************************************************** * copy a whole screen of text mode data into video memory, assume that screen * width is 80 or 40 * * @param src memory block with the same size as text mode video memory() *****************************************************************************/ static inline void vga_flush_screen(void* src) { u32* _src = src; u32* dst = (u32*)K_PHY2LIN(V_MEM_BASE); for (int i = 0; i < SCR_SIZE * sizeof(u16) / sizeof(u32); ++ i) { *dst ++ = *_src ++; } } /***************************************************************************** * copy a whole screen of text mode data into video memory, assume that screen * width is 80 or 40 * * @param src memory block with the same size as text mode video memory() *****************************************************************************/ static inline void vga_flush_line(void* src, int line_no) { u32* _src = src; u32* dst = (u32*)K_PHY2LIN(V_MEM_BASE + line_no * SCR_WIDTH * 2); for (int i = 0; i < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++ i) { *dst ++ = *_src ++; } } static inline void vga_flush_blankline(int line_no) { u32* dst = (u32*)K_PHY2LIN(V_MEM_BASE + line_no * SCR_WIDTH * 2); for (int i = 0; i < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++ i) { *dst ++ = (BLANK << 16) | BLANK; } } /***************************************************************************** * tty - vga driver *****************************************************************************/ static u16 pagebuf[3][SCR_BUFSIZE]; void vga_tty_init(NTTY* tty) { assert(tty->driver_type == 1); assert(tty->output_buf); vga_buf* vga = tty->output_buf; // vga->buf = (void*)do_kmalloc(sizeof(u16) * SCR_BUFSIZE); vga->buf = (void*)pagebuf[0]; // kprintf("malloced %p %p %p\n", vga->buf, &vga->buf, &vga->scr_top_line); vga->cur_col = vga->cur_row = 0; // buf->max_line = SCR_BUFSIZE / SCR_WIDTH; vga->scr_top_line = vga->scr_cur_line = 0; vga->head_line = 0; u32* ptr_buf = (u32*) vga->buf; for (int i = 0; i < SCR_BUFSIZE * sizeof(u16) / sizeof(u32); ++i) { ptr_buf[i] = (BLANK << 16) | BLANK; // bg-black, fg-white, ascii-space } kprintf("%p 0x%x %d\n", vga->buf, ((u32*)vga->buf)[20], vga->scr_cur_line); } #define INDEX(row, col) ((row) * SCR_WIDTH + (col)) #define NEXTLINE(row) (((row) + 1) % SCR_MAXLINE) #define LASTLINE(row) (((row) - 1) >= 0 ? ((row) - 1) % SCR_MAXLINE : SCR_MAXLINE) static void newline(vga_buf* vgabuf) { vgabuf->cur_col = 0; // kprintf("bf %x\n", vgabuf->scr_cur_line); vgabuf->scr_cur_line = NEXTLINE(vgabuf->scr_cur_line); // kprintf("af %x\n", vgabuf->scr_cur_line); vgabuf->cur_row = abs(vgabuf->scr_cur_line - vgabuf->scr_top_line); if (vgabuf->cur_row == SCR_HEIGHT) { // auto scroll vgabuf->scr_top_line = NEXTLINE(vgabuf->scr_top_line); if(vgabuf->scr_cur_line == vgabuf->head_line) { vgabuf->head_line = NEXTLINE(vgabuf->head_line); // remember to fill blank the old line u32* ptr_buf = (u32*) (vgabuf->buf + sizeof(u16) * vgabuf->head_line * SCR_WIDTH); for (int i = 0; i < SCR_WIDTH * sizeof(u16) / sizeof(u32); ++i) { *ptr_buf++ = (BLANK << 16) | BLANK; // bg-black, fg-white, ascii-space } } } } void vga_tty_write(NTTY* tty, char ch) { // assert(tty->driver_type == 1); // assert(tty->output_buf); vga_buf* vga = tty->output_buf; u16* buf = vga->buf; // kprintf("vga_tty_write %c to %d %d\n", ch, vga->scr_cur_line, vga->cur_col); switch (ch) { case '\n': newline(vga); break; case '\r': vga->cur_col = 0; break; case '\b': // this implementation is mimic to usual linux shell // it moves cursor left but neither crosses line nor delete character if (vga->cur_col > 0) { vga->cur_col --; } break; default: buf[INDEX(vga->scr_cur_line, vga->cur_col)] = MAKE_CELL(DEFAULT_CHAR_COLOR, ch); vga->cur_col ++; if (vga->cur_col == SCR_WIDTH) { newline(vga); } break; } vga->cur_row = abs(vga->scr_cur_line - vga->scr_top_line); // kprintf("row: %d; ", vga->cur_row); } void vga_tty_flush(NTTY* tty) { vga_buf* vga = tty->output_buf; u16* buf = vga->buf; int i, cur_line; vga_set_cursor(INDEX(vga->cur_row, vga->cur_col)); if (vga->cur_row == SCR_WIDTH - 1) { vga_flush_screen(&buf[INDEX(vga->scr_top_line, 0)]); } else { cur_line = vga->scr_top_line; for (i = 0; i <= vga->cur_row; ++ i){ vga_flush_line(&buf[INDEX(cur_line, 0)], i); cur_line = NEXTLINE(cur_line); } for (; i < SCR_WIDTH; ++ i) { vga_flush_blankline(i); } } // kprintf("flush: row=%d, top=%d, cur=%d\n", vga->cur_row, vga->scr_top_line, vga->scr_cur_line); } void vga_tty_scroll(NTTY* tty, int direction) { vga_buf* vga = tty->output_buf; u16* buf = vga->buf; if (direction > 0) { // down if (vga->scr_top_line == vga->scr_cur_line) return; vga->scr_top_line = NEXTLINE(vga->scr_top_line); } else { if (vga->scr_top_line == vga->head_line) return; vga->scr_top_line = LASTLINE(vga->scr_top_line); } vga->cur_row = abs(vga->scr_cur_line - vga->scr_top_line); if (vga->cur_row >= SCR_HEIGHT) { vga_disable_cursor(); } else { vga_enable_cursor(0, 15); } } void vga_scroll_to_cur(NTTY* tty) { vga_buf* vga = tty->output_buf; u16* buf = vga->buf; // vga->scr_top_line = vga->scr_cur_line } void vga_tty_select(NTTY* tty) { // }