New developer version 0.6.8; added select () function; added demonstrating example...
[ZeXOS.git] / kernel / core / tty.c
blobb6bd5792b242995374d991570b442b58a63b10b8
1 /*
2 * ZeX/OS
3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <build.h>
23 #include <system.h>
24 #include <string.h>
25 #include <vfs.h>
27 #ifdef ARCH_i386 /* i386 specific things */
28 extern int gets (void);
29 extern unsigned short *textmemptr;
30 #endif
31 extern int attrib;
32 extern int csr_x, csr_y;
33 extern unsigned char vgagui;
35 static char con_screen[TTY_CON_BUF]; /* console buffer for image of screen */
36 static unsigned short tty_count; /* number of created ttys */
37 tty_font_t tty_font; /* global font settings */
38 tty_char_t tty_char; /* global character array settings */
40 tty_t tty_list; /* list for all created ttys */
41 tty_t *tty0, *tty1; /* structures for default ttys (0, 1) */
43 static unsigned task_tty ();
45 /* setup of font */
46 bool tty_font_set (char *c, unsigned char x, unsigned char y)
48 if (!c || !x || !y)
49 return 0;
51 tty_font.c = c;
52 tty_font.x = x;
53 tty_font.y = y;
55 return 1;
58 /* setup of character array */
59 bool tty_char_set (unsigned short x, unsigned short y)
61 if ((x * y * 2) > TTY_CON_BUF)
62 return 0;
64 tty_char.x = x;
65 tty_char.y = y;
67 return 1;
70 /* clear selected screen */
71 bool tty_cls (tty_t *tty)
73 if (!tty)
74 return 0;
76 if (!tty->screen)
77 return 0;
79 memset (tty->screen, 0, tty_char.x * tty_char.y * 2);
81 tty->screen_x = 0;
82 tty->screen_y = 0;
84 if (tty != currtty)
85 return 1;
87 #ifdef ARCH_i386
88 if (vgagui) {
89 if (vgagui == 2)
90 video_gfx_cls (0);
92 return 1;
95 csr_x = 0;
96 csr_y = 0;
98 video_scroll ();
99 video_move_csr ();
100 #endif
101 video_cls ();
103 return 1;
106 /* lock manipulation with selected tty */
107 bool tty_lock (tty_t *tty)
109 if (!tty)
110 return 0;
112 tty->active = false;
114 return 1;
117 /* unlock manipulation with selected tty */
118 bool tty_unlock (tty_t *tty)
120 if (!tty)
121 return 0;
123 tty->active = true;
125 return 1;
128 /* startup function for tty init */
129 bool tty_startup ()
131 tty_t *tty = tty0;
133 if (tty == NULL)
134 return 0;
136 currtty = tty;
138 strcpy (currtty->pwd, (char *) env_get ("PWD"));
140 currtty = tty;
142 env_set ("PWD", tty->pwd);
144 /* always default colors */
145 attrib = 0x07;
147 /* clear screen*/
148 video_cls ();
150 return 1;
153 /* change current tty to selected one */
154 bool tty_change (tty_t *tty)
156 #ifndef ARCH_i386
157 return 0;
158 #endif
159 if (tty == NULL)
160 return 0;
162 #ifdef ARCH_i386
163 /* redraw screen with selected tty */
164 memcpy (textmemptr, tty->screen, tty_char.x * tty_char.y * 2);
166 csr_x = tty->screen_x;
167 csr_y = tty->screen_y;
169 video_move_csr ();
170 #endif
171 strcpy (currtty->pwd, (char *) env_get ("PWD"));
173 if (currtty->user && currtty->user->name)
174 strcpy (currtty->user->name, (char *) env_get ("USER"));
176 currtty = tty;
178 env_set ("PWD", tty->pwd);
180 if (tty->user)
181 env_set ("USER", tty->user->name);
183 return 1;
186 /* move cursor position to selected place */
187 bool tty_gotoxy (tty_t *tty, unsigned char x, unsigned char y)
189 if (tty == NULL)
190 return 0;
192 if (x >= tty_char.x || y >= tty_char.y)
193 return 0;
195 video_gotoxy (x, y);
197 tty->screen_x = x;
198 tty->screen_y = y;
200 return 1;
203 /* find wanted tty by name */
204 tty_t *tty_find (char *name)
206 tty_t *tty;
208 for (tty = tty_list.next; tty != &tty_list; tty = tty->next) {
209 if (!strcmp (tty->name, name))
210 return tty;
213 return NULL;
216 /* find tty by task */
217 tty_t *tty_findbytask (task_t *task)
219 tty_t *tty;
221 for (tty = tty_list.next; tty != &tty_list; tty = tty->next) {
222 if (tty->task == task)
223 return tty;
226 return NULL;
229 /* display list of created tty consoles */
230 void tty_listview ()
232 unsigned short id = 1;
234 tty_t *tty;
236 for (tty = tty_list.next; tty != &tty_list; tty = tty->next) {
237 printf ("%d.\t%s\t%s\n", id, tty->name, currtty == tty ? "<- current" : "");
239 id ++;
243 /* enable logging for TTY */
244 int tty_log_create (tty_t *tty, unsigned short len)
246 if (!tty || !len)
247 return 0;
249 tty->log = (tty_log_t *) kmalloc (sizeof (tty_log_t));
251 if (!tty->log)
252 return 0;
254 tty->log->buf = (char *) kmalloc (sizeof (char) * len);
256 if (!tty->log->buf) {
257 kfree (tty->log);
258 return 0;
261 tty->log->len = len;
262 tty->log->pos = 0;
264 return 1;
267 /* main function for print strings into selected tty */
268 bool tty_write (tty_t *tty, char *str, unsigned len)
270 if (!tty)
271 return 0;
273 unsigned l = 0;
274 while (l != len) {
275 if (!tty_putnch (tty, str[l]))
276 break;
278 l ++;
281 return 1;
284 /* read strings from selected tty */
285 int tty_read (tty_t *tty, char *str, unsigned len)
287 if (!tty || !str)
288 return 0;
290 /* create log buffer for current tty when not exist */
291 if (!tty->log)
292 if (!tty_log_create (tty, 512))
293 return 0;
295 unsigned l = len;
297 if (l > tty->log->pos)
298 l = tty->log->pos;
300 memcpy (str, tty->log->buf, l);
302 tty->log->pos -= l;
304 return l;
307 /* print character to current tty */
308 bool tty_putch (char c)
310 tty_putnch (currtty, c);
312 return 1;
315 /* print character to selected tty */
316 bool tty_putnch (tty_t *tty, char c)
318 /* we wont null character */
319 if (!c)
320 return 0;
322 switch (c) {
323 case '\n':
324 tty->screen_y ++;
325 tty->screen_x = 0;
326 break;
327 case '\b':
328 if (tty->screen_x)
329 tty->screen_x --;
331 /* save font attributes (colors) */
332 tty->screen[(tty->screen_x+(tty->screen_y*tty_char.x))*2] = ' ';
333 /* save character into buffer */
334 tty->screen[((tty->screen_x+(tty->screen_y*tty_char.x))*2)+1] = attrib;
336 break;
337 case '\t':
338 tty->screen_x = (tty->screen_x + 8) & ~7;
339 break;
340 default:
341 /* save font attributes (colors) */
342 tty->screen[(tty->screen_x+(tty->screen_y*tty_char.x))*2] = c;
343 /* save character into buffer */
344 tty->screen[((tty->screen_x+(tty->screen_y*tty_char.x))*2)+1] = attrib;
345 tty->screen_x ++;
346 break;
349 if (tty->screen_x >= tty_char.x) {
350 tty->screen_x -= tty_char.x;
351 tty->screen_y ++;
354 if (tty->screen_y >= tty_char.y) {
355 unsigned i;
356 /* save old screen, but with one line offset */
357 for (i = 0; i < (tty_char.x * tty_char.y * 2) - (tty_char.x * 2); i ++)
358 con_screen[i] = tty->screen[i+(tty_char.x * 2)];
359 /* copy new image into tty screen */
360 for (i = 0; i < (tty_char.x * tty_char.y * 2); i ++)
361 tty->screen[i] = con_screen[i];
363 tty->screen_y = tty_char.y - 1;
366 if (tty == currtty) {
367 if (!vgagui)
368 video_putch (c);
371 if (tty->log) {
372 if (tty->log->pos+1 == tty->log->len) {
373 memcpy (tty->log->buf, tty->log->buf+1, tty->log->len-1);
374 tty->log->buf[tty->log->pos] = c;
375 } else
376 tty->log->buf[tty->log->pos ++] = c;
379 return 1;
382 /* create Message Of The Day in /etc/motd */
383 bool tty_motd ()
385 vfs_list_add ("motd", VFS_FILEATTR_FILE | VFS_FILEATTR_READ | VFS_FILEATTR_SYSTEM, "/etc/");
387 char *motd = "\t\t\t\tWelcome !\n"
388 "This is ZeX/OS - operating system created by Tomas 'ZeXx86' Jedrzejek\n"
389 "Please visit web page www.zexos.org for more information ..\n"
390 "Latest source code is available on git repository: git://repo.or.cz/ZeXOS.git\n"
391 "You can display list of the built-in commands by \"help\".\n"
392 "Default login name is \"root\" secured by password \"root\".\n";
394 vfs_content_t content;
395 content.ptr = motd;
396 content.len = strlen (motd);
398 vfs_mmap ("/etc/motd", 9, &content);
400 video_color (15, 0);
402 vfs_cat ("/etc/motd", 9);
404 video_color (7, 0);
406 return 1;
409 /* virtual terminal (device handler) */
410 bool vterm_acthandler (unsigned act, char *block, unsigned block_len)
412 switch (act) {
413 case DEV_ACT_INIT:
415 dev_flags_t *flags = (dev_flags_t *) block;
417 if (!flags)
418 return 0;
420 if (block_len != sizeof (dev_flags_t))
421 return 0;
423 tty_t *tty = tty_find ((char *) flags->iomem);
425 if (!tty)
426 return 0;
428 flags->iomem = (void *) tty->screen;
429 flags->iolen = tty_char.x * tty_char.y * 2;
431 return 1;
433 break;
436 return 0;
439 /* create new tty console */
440 tty_t *tty_create ()
442 /* Software limit - max. 1K of ttys */
443 if (tty_count > TTY_COUNT_MAX)
444 return 0;
446 char name[8];
447 sprintf (name, "tty%d", tty_count);
449 unsigned name_len = strlen (name);
451 /* alloc and init context */
452 tty_t *tty = (tty_t *) kmalloc (sizeof (tty_t));
454 if (!tty)
455 return 0;
457 memset (tty, 0, sizeof (tty_t));
459 tty->screen = (char *) kmalloc (tty_char.x * tty_char.y * 2);
461 if (!tty->screen) {
462 kfree (tty);
463 return 0;
466 tty->name = (char *) kmalloc (sizeof (char) * name_len + 1);
468 if (!tty->name) {
469 kfree (tty->screen);
470 kfree (tty);
471 return 0;
474 memcpy (tty->name, name, name_len);
475 tty->name[name_len] = '\0';
477 memset (tty->screen, 0, tty_char.x * tty_char.y * 2);
479 tty->screen_x = 0;
480 tty->screen_y = 0;
482 tty->logged = false;
484 tty->active = true;
486 tty->log = 0;
488 strcpy (tty->pwd, (char *) env_get ("PWD"));
490 tty->task = (task_t *) task_create (name, (unsigned) task_tty, 32);
492 /* add into list */
493 tty->next = &tty_list;
494 tty->prev = tty_list.prev;
495 tty->prev->next = tty;
496 tty->next->prev = tty;
498 /* create device which correspnd with current TTY */
499 dev_register (name, "Virtual terminal", DEV_ATTR_CHAR, (dev_handler_t *) &vterm_acthandler);
501 tty_count ++;
503 return tty;
506 /* thread for running tty consoles - handle selected console */
507 void task_thread (tty_t *tty)
509 schedule ();
511 if (!tty)
512 return;
514 if (tty != currtty)
515 return;
517 if (tty->active) {
518 /* handle console on kernel level */
519 int id = gets ();
521 if (id == 1)
522 if (tty->user) {
523 console (id);
524 } else
525 getlogin (id);
527 /* VESA mode - graphical font */
528 if (vgagui == 2) {
529 unsigned i = 0;
530 unsigned j = 0;
531 unsigned k = 0;
532 unsigned m = tty_char.x * tty_char.y;
534 while (i < m) {
535 gputch (1+(j*tty_font.x), 11+(k*(tty_font.y+1)), vesa_16cto16b (tty->screen[i*2+1] & 0x0F), tty->screen[i*2]);
537 j ++;
539 if (j >= tty_char.x) {
540 j = 0;
541 k ++;
544 i ++;
547 video_gfx_fbswap ();
552 /* startup function for created tty console */
553 static unsigned task_tty ()
555 tty_t *tty = tty_findbytask (_curr_task);
557 if (!tty)
558 return 0;
560 for (;;)
561 task_thread (tty);
564 /* change tty console to next (+) or previous (-) in list */
565 void tty_switch (char act)
567 switch (act) {
568 case '+':
570 tty_t *tty = currtty->next;
572 if (tty == &tty_list)
573 tty = tty_list.next;
575 if (tty)
576 tty_change (tty);
578 break;
580 case '-':
582 tty_t *tty = currtty->prev;
584 if (tty == &tty_list)
585 tty = tty_list.prev;
587 if (tty)
588 tty_change (tty);
590 break;
595 /* special function for initialization of graphical tty */
596 tty_t *gtty_init ()
598 tty_t *tty = tty_create ();
600 tty_change (tty);
602 return tty;
605 /* initialization of tty */
606 unsigned int init_tty ()
608 /* pre-set tty list */
609 tty_list.next = &tty_list;
610 tty_list.prev = &tty_list;
612 /* default values */
613 tty_count = 0;
615 tty_font_set ((char *) font5x8, 5, 8);
617 switch (vgagui) {
618 case 0: /* VGA-Textual console */
619 tty_char_set (80, 25);
620 break;
621 case 1: /* VGA console */
622 tty_char_set (53, 18);
623 break;
624 case 2: /* VESA concole */
625 tty_char_set (80, 65);
626 break;
629 video_color (7, 0);
631 /* create consoles */
632 tty0 = tty_create ();
634 if (!tty0)
635 return 0;
637 #ifdef ARCH_i386
638 tty1 = tty_create ();
640 if (!tty1)
641 return 0;
642 #endif
643 tty_startup ();
645 /* printf MOTD into TTY0 console */
646 tty_motd ();
648 /* then print login messages */
649 tty_write (tty0, "\nlogin: ", 8);
650 #ifdef ARCH_i386
651 tty_write (tty1, "\nlogin: ", 8);
652 #endif
653 return 1;