summaryrefslogtreecommitdiff
path: root/kern/pts.c
diff options
context:
space:
mode:
Diffstat (limited to 'kern/pts.c')
-rw-r--r--kern/pts.c96
1 files changed, 92 insertions, 4 deletions
diff --git a/kern/pts.c b/kern/pts.c
index 2d51620..2964a25 100644
--- a/kern/pts.c
+++ b/kern/pts.c
@@ -40,6 +40,15 @@ pts_t* active_pts = NULL;
spl_t pts_lock = SPL_INIT;
queue_t* all_pts = NULL;
+pts_t kernel_pts;
+
+void setup_pts() {
+ pts_init(&kernel_pts);
+ get_current()->pts = &kernel_pts;
+ kernel_pts.refcount++; /* kernel's refcount for all kths */
+ active_pts = &kernel_pts;
+}
+
void pts_init(pts_t* pts) {
pts->cur_x = pts->cur_y = 0;
pts->cur_color = DEFAULT_COLOR;
@@ -52,10 +61,29 @@ void pts_init(pts_t* pts) {
pts->input_cv = CV_INIT;
pts->kh_r_pos = pts->kh_w_pos = 0;
pts->chr_r_pos = pts->chr_w_pos = 0;
+ pts->forward_tab = 0;
pts->lock = MUTEX_INIT;
+ pts->pvs = NULL;
pts->refcount = 0;
- queue_insert_head(&all_pts, &pts->pts_link);
+ queue_insert_tail(&all_pts, &pts->pts_link);
+}
+
+void switch_pts(pts_t* new_pts) {
+ int old_if = spl_lock(&pts_lock);
+ pts_t* pts = active_pts;
+ active_pts = new_pts;
+ if (pts->refcount == 0) {
+ queue_detach(&all_pts, &pts->pts_link);
+ sfree(pts, sizeof(pts_t));
+ }
+ memcpy(console_mem, new_pts->mem, sizeof(new_pts->mem));
+ int pos = new_pts->cur_y * CONSOLE_WIDTH + new_pts->cur_x;
+ outb(CRTC_IDX_REG, CRTC_CURSOR_LSB_IDX);
+ outb(CRTC_DATA_REG, pos & 0xff);
+ outb(CRTC_IDX_REG, CRTC_CURSOR_MSB_IDX);
+ outb(CRTC_DATA_REG, pos >> 8);
+ spl_unlock(&pts_lock, old_if);
}
/**
@@ -117,6 +145,13 @@ static inline void draw_char(pts_t* pts,
}
int putbyte(char ch) {
+ if (active_pts == NULL) {
+ /* this only happens when panicking before setup_pts */
+ active_pts = &kernel_pts;
+ pts_putbyte(&kernel_pts, ch);
+ active_pts = NULL;
+ return 0;
+ }
return pts_putbyte(get_current()->pts, ch);
}
@@ -202,18 +237,71 @@ void pts_get_cursor(pts_t* pts, int* row, int* col) {
*col = pts->cur_x;
}
+int pts_print_at(pts_t* pts, int len, va_t buf, int row, int col, int color) {
+ int old_row, old_col;
+ int old_color;
+ pts_get_cursor(pts, &old_row, &old_col);
+ if (pts_set_cursor(pts, row, col) != 0) {
+ goto bad_pos;
+ }
+ pts_get_term_color(pts, &old_color);
+ if (pts_set_term_color(pts, color) != 0) {
+ goto bad_color;
+ }
+ if (print_buf_from_user(pts, buf, len) != 0) {
+ goto bad_print;
+ }
+ pts_set_term_color(pts, old_color);
+ pts_set_cursor(pts, old_row, old_col);
+ return 0;
+
+bad_print:
+ pts_set_term_color(pts, old_color);
+bad_color:
+ pts_set_cursor(pts, old_row, old_col);
+bad_pos:
+ return -1;
+}
+
/**
* @brief keyboard inturrupt handler
*/
void kbd_handler_real(stack_frame_t* f) {
unsigned char sc = inb(KEYBOARD_PORT);
pic_acknowledge(KBD_IRQ);
+ pts_t* pts = active_pts;
+ int should_insert = 0;
kh_type kh = process_scancode(sc);
- if (pv_inject_irq(f, KEY_IDT_ENTRY, kh) == 0) {
+ if (KH_HASDATA(kh) && KH_ISMAKE(kh)) {
+ should_insert = 1;
+ if (KH_GETCHAR(kh) == KHE_TAB) {
+ if (KH_SHIFT(kh) != 0) {
+ if (pts->forward_tab == 0) {
+ pts->forward_tab = 1;
+ return;
+ }
+ /* else forward shift+tab to client */
+ } else if (KH_CTL(kh) != 0) {
+ if (pts->forward_tab != 0) {
+ pts->forward_tab = 0;
+ return;
+ }
+ } else if (pts->forward_tab == 0) {
+ pts_t* new_pts =
+ queue_data(pts->pts_link.next, pts_t, pts_link);
+ if (new_pts != pts) {
+ switch_pts(new_pts);
+ }
+ return;
+ }
+ }
+ }
+ if (pts->pvs != NULL) {
+ pv_t* pv = queue_data(pts->pvs, pv_t, pts_link);
+ pv_pend_irq(pv, KEY_IDT_ENTRY, kh);
return;
}
- pts_t* pts = active_pts;
- if (KH_HASDATA(kh) && KH_ISMAKE(kh)) {
+ if (should_insert != 0) {
int next_w_pos = (pts->kh_w_pos + 1) % KH_RING_SIZE;
if (next_w_pos != pts->kh_r_pos) {
pts->kh_ring[pts->kh_w_pos] = kh;