summaryrefslogtreecommitdiffstats
path: root/src/kernel/chr_drv/console.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/chr_drv/console.c')
-rw-r--r--src/kernel/chr_drv/console.c710
1 files changed, 710 insertions, 0 deletions
diff --git a/src/kernel/chr_drv/console.c b/src/kernel/chr_drv/console.c
new file mode 100644
index 0000000..2529569
--- /dev/null
+++ b/src/kernel/chr_drv/console.c
@@ -0,0 +1,710 @@
1/*
2 * linux/kernel/console.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7/*
8 * console.c
9 *
10 * This module implements the console io functions
11 * 'void con_init(void)'
12 * 'void con_write(struct tty_queue * queue)'
13 * Hopefully this will be a rather complete VT102 implementation.
14 *
15 * Beeping thanks to John T Kohl.
16 */
17
18/*
19 * NOTE!!! We sometimes disable and enable interrupts for a short while
20 * (to put a word in video IO), but this will work even for keyboard
21 * interrupts. We know interrupts aren't enabled when getting a keyboard
22 * interrupt, as we use trap-gates. Hopefully all is well.
23 */
24
25/*
26 * Code to check for different video-cards mostly by Galen Hunt,
27 * <g-hunt@ee.utah.edu>
28 */
29
30#include <linux/sched.h>
31#include <linux/tty.h>
32#include <asm/io.h>
33#include <asm/system.h>
34
35/*
36 * These are set up by the setup-routine at boot-time:
37 */
38
39#define ORIG_X (*(unsigned char *)0x90000)
40#define ORIG_Y (*(unsigned char *)0x90001)
41#define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004)
42#define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff)
43#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8)
44#define ORIG_VIDEO_LINES (25)
45#define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008)
46#define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a)
47#define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c)
48
49#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */
50#define VIDEO_TYPE_CGA 0x11 /* CGA Display */
51#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */
52#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */
53
54#define NPAR 16
55
56extern void keyboard_interrupt(void);
57
58static unsigned char video_type; /* Type of display being used */
59static unsigned long video_num_columns; /* Number of text columns */
60static unsigned long video_size_row; /* Bytes per row */
61static unsigned long video_num_lines; /* Number of test lines */
62static unsigned char video_page; /* Initial video page */
63static unsigned long video_mem_start; /* Start of video RAM */
64static unsigned long video_mem_end; /* End of video RAM (sort of) */
65static unsigned short video_port_reg; /* Video register select port */
66static unsigned short video_port_val; /* Video register value port */
67static unsigned short video_erase_char; /* Char+Attrib to erase with */
68
69static unsigned long origin; /* Used for EGA/VGA fast scroll */
70static unsigned long scr_end; /* Used for EGA/VGA fast scroll */
71static unsigned long pos;
72static unsigned long x,y;
73static unsigned long top,bottom;
74static unsigned long state=0;
75static unsigned long npar,par[NPAR];
76static unsigned long ques=0;
77static unsigned char attr=0x07;
78
79static void sysbeep(void);
80
81/*
82 * this is what the terminal answers to a ESC-Z or csi0c
83 * query (= vt100 response).
84 */
85#define RESPONSE "\033[?1;2c"
86
87/* NOTE! gotoxy thinks x==video_num_columns is ok */
88static inline void gotoxy(unsigned int new_x,unsigned int new_y)
89{
90 if (new_x > video_num_columns || new_y >= video_num_lines)
91 return;
92 x=new_x;
93 y=new_y;
94 pos=origin + y*video_size_row + (x<<1);
95}
96
97static inline void set_origin(void)
98{
99 cli();
100 outb_p(12, video_port_reg);
101 outb_p(0xff&((origin-video_mem_start)>>9), video_port_val);
102 outb_p(13, video_port_reg);
103 outb_p(0xff&((origin-video_mem_start)>>1), video_port_val);
104 sti();
105}
106
107static void scrup(void)
108{
109 if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM)
110 {
111 if (!top && bottom == video_num_lines) {
112 origin += video_size_row;
113 pos += video_size_row;
114 scr_end += video_size_row;
115 if (scr_end > video_mem_end) {
116 __asm__("cld\n\t"
117 "rep\n\t"
118 "movsl\n\t"
119 "movl video_num_columns,%1\n\t"
120 "rep\n\t"
121 "stosw"
122 ::"a" (video_erase_char),
123 "c" ((video_num_lines-1)*video_num_columns>>1),
124 "D" (video_mem_start),
125 "S" (origin)
126 );
127 scr_end -= origin-video_mem_start;
128 pos -= origin-video_mem_start;
129 origin = video_mem_start;
130 } else {
131 __asm__("cld\n\t"
132 "rep\n\t"
133 "stosw"
134 ::"a" (video_erase_char),
135 "c" (video_num_columns),
136 "D" (scr_end-video_size_row)
137 );
138 }
139 set_origin();
140 } else {
141 __asm__("cld\n\t"
142 "rep\n\t"
143 "movsl\n\t"
144 "movl video_num_columns,%%ecx\n\t"
145 "rep\n\t"
146 "stosw"
147 ::"a" (video_erase_char),
148 "c" ((bottom-top-1)*video_num_columns>>1),
149 "D" (origin+video_size_row*top),
150 "S" (origin+video_size_row*(top+1))
151 );
152 }
153 }
154 else /* Not EGA/VGA */
155 {
156 __asm__("cld\n\t"
157 "rep\n\t"
158 "movsl\n\t"
159 "movl video_num_columns,%%ecx\n\t"
160 "rep\n\t"
161 "stosw"
162 ::"a" (video_erase_char),
163 "c" ((bottom-top-1)*video_num_columns>>1),
164 "D" (origin+video_size_row*top),
165 "S" (origin+video_size_row*(top+1))
166 );
167 }
168}
169
170static void scrdown(void)
171{
172 if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM)
173 {
174 __asm__("std\n\t"
175 "rep\n\t"
176 "movsl\n\t"
177 "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
178 "movl video_num_columns,%%ecx\n\t"
179 "rep\n\t"
180 "stosw"
181 ::"a" (video_erase_char),
182 "c" ((bottom-top-1)*video_num_columns>>1),
183 "D" (origin+video_size_row*bottom-4),
184 "S" (origin+video_size_row*(bottom-1)-4)
185 );
186 }
187 else /* Not EGA/VGA */
188 {
189 __asm__("std\n\t"
190 "rep\n\t"
191 "movsl\n\t"
192 "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
193 "movl video_num_columns,%%ecx\n\t"
194 "rep\n\t"
195 "stosw"
196 ::"a" (video_erase_char),
197 "c" ((bottom-top-1)*video_num_columns>>1),
198 "D" (origin+video_size_row*bottom-4),
199 "S" (origin+video_size_row*(bottom-1)-4)
200 );
201 }
202}
203
204static void lf(void)
205{
206 if (y+1<bottom) {
207 y++;
208 pos += video_size_row;
209 return;
210 }
211 scrup();
212}
213
214static void ri(void)
215{
216 if (y>top) {
217 y--;
218 pos -= video_size_row;
219 return;
220 }
221 scrdown();
222}
223
224static void cr(void)
225{
226 pos -= x<<1;
227 x=0;
228}
229
230static void del(void)
231{
232 if (x) {
233 pos -= 2;
234 x--;
235 *(unsigned short *)pos = video_erase_char;
236 }
237}
238
239static void csi_J(int par)
240{
241 long count;
242 long start;
243
244 switch (par) {
245 case 0: /* erase from cursor to end of display */
246 count = (scr_end-pos)>>1;
247 start = pos;
248 break;
249 case 1: /* erase from start to cursor */
250 count = (pos-origin)>>1;
251 start = origin;
252 break;
253 case 2: /* erase whole display */
254 count = video_num_columns * video_num_lines;
255 start = origin;
256 break;
257 default:
258 return;
259 }
260 __asm__("cld\n\t"
261 "rep\n\t"
262 "stosw\n\t"
263 ::"c" (count),
264 "D" (start),"a" (video_erase_char)
265 );
266}
267
268static void csi_K(int par)
269{
270 long count;
271 long start;
272
273 switch (par) {
274 case 0: /* erase from cursor to end of line */
275 if (x>=video_num_columns)
276 return;
277 count = video_num_columns-x;
278 start = pos;
279 break;
280 case 1: /* erase from start of line to cursor */
281 start = pos - (x<<1);
282 count = (x<video_num_columns)?x:video_num_columns;
283 break;
284 case 2: /* erase whole line */
285 start = pos - (x<<1);
286 count = video_num_columns;
287 break;
288 default:
289 return;
290 }
291 __asm__("cld\n\t"
292 "rep\n\t"
293 "stosw\n\t"
294 ::"c" (count),
295 "D" (start),"a" (video_erase_char)
296 );
297}
298
299void csi_m(void)
300{
301 int i;
302
303 for (i=0;i<=npar;i++)
304 switch (par[i]) {
305 case 0:attr=0x07;break;
306 case 1:attr=0x0f;break;
307 case 4:attr=0x0f;break;
308 case 7:attr=0x70;break;
309 case 27:attr=0x07;break;
310 }
311}
312
313static inline void set_cursor(void)
314{
315 cli();
316 outb_p(14, video_port_reg);
317 outb_p(0xff&((pos-video_mem_start)>>9), video_port_val);
318 outb_p(15, video_port_reg);
319 outb_p(0xff&((pos-video_mem_start)>>1), video_port_val);
320 sti();
321}
322
323static void respond(struct tty_struct * tty)
324{
325 char * p = RESPONSE;
326
327 cli();
328 while (*p) {
329 PUTCH(*p,tty->read_q);
330 p++;
331 }
332 sti();
333 copy_to_cooked(tty);
334}
335
336static void insert_char(void)
337{
338 int i=x;
339 unsigned short tmp, old = video_erase_char;
340 unsigned short * p = (unsigned short *) pos;
341
342 while (i++<video_num_columns) {
343 tmp=*p;
344 *p=old;
345 old=tmp;
346 p++;
347 }
348}
349
350static void insert_line(void)
351{
352 int oldtop,oldbottom;
353
354 oldtop=top;
355 oldbottom=bottom;
356 top=y;
357 bottom = video_num_lines;
358 scrdown();
359 top=oldtop;
360 bottom=oldbottom;
361}
362
363static void delete_char(void)
364{
365 int i;
366 unsigned short * p = (unsigned short *) pos;
367
368 if (x>=video_num_columns)
369 return;
370 i = x;
371 while (++i < video_num_columns) {
372 *p = *(p+1);
373 p++;
374 }
375 *p = video_erase_char;
376}
377
378static void delete_line(void)
379{
380 int oldtop,oldbottom;
381
382 oldtop=top;
383 oldbottom=bottom;
384 top=y;
385 bottom = video_num_lines;
386 scrup();
387 top=oldtop;
388 bottom=oldbottom;
389}
390
391static void csi_at(unsigned int nr)
392{
393 if (nr > video_num_columns)
394 nr = video_num_columns;
395 else if (!nr)
396 nr = 1;
397 while (nr--)
398 insert_char();
399}
400
401static void csi_L(unsigned int nr)
402{
403 if (nr > video_num_lines)
404 nr = video_num_lines;
405 else if (!nr)
406 nr = 1;
407 while (nr--)
408 insert_line();
409}
410
411static void csi_P(unsigned int nr)
412{
413 if (nr > video_num_columns)
414 nr = video_num_columns;
415 else if (!nr)
416 nr = 1;
417 while (nr--)
418 delete_char();
419}
420
421static void csi_M(unsigned int nr)
422{
423 if (nr > video_num_lines)
424 nr = video_num_lines;
425 else if (!nr)
426 nr=1;
427 while (nr--)
428 delete_line();
429}
430
431static int saved_x=0;
432static int saved_y=0;
433
434static void save_cur(void)
435{
436 saved_x=x;
437 saved_y=y;
438}
439
440static void restore_cur(void)
441{
442 gotoxy(saved_x, saved_y);
443}
444
445void con_write(struct tty_struct * tty)
446{
447 int nr;
448 char c;
449
450 nr = CHARS(tty->write_q);
451 while (nr--) {
452 GETCH(tty->write_q,c);
453 switch(state) {
454 case 0:
455 if (c>31 && c<127) {
456 if (x>=video_num_columns) {
457 x -= video_num_columns;
458 pos -= video_size_row;
459 lf();
460 }
461 __asm__("movb attr,%%ah\n\t"
462 "movw %%ax,%1\n\t"
463 ::"a" (c),"m" (*(short *)pos)
464 );
465 pos += 2;
466 x++;
467 } else if (c==27)
468 state=1;
469 else if (c==10 || c==11 || c==12)
470 lf();
471 else if (c==13)
472 cr();
473 else if (c==ERASE_CHAR(tty))
474 del();
475 else if (c==8) {
476 if (x) {
477 x--;
478 pos -= 2;
479 }
480 } else if (c==9) {
481 c=8-(x&7);
482 x += c;
483 pos += c<<1;
484 if (x>video_num_columns) {
485 x -= video_num_columns;
486 pos -= video_size_row;
487 lf();
488 }
489 c=9;
490 } else if (c==7)
491 sysbeep();
492 break;
493 case 1:
494 state=0;
495 if (c=='[')
496 state=2;
497 else if (c=='E')
498 gotoxy(0,y+1);
499 else if (c=='M')
500 ri();
501 else if (c=='D')
502 lf();
503 else if (c=='Z')
504 respond(tty);
505 else if (x=='7')
506 save_cur();
507 else if (x=='8')
508 restore_cur();
509 break;
510 case 2:
511 for(npar=0;npar<NPAR;npar++)
512 par[npar]=0;
513 npar=0;
514 state=3;
515 if ((ques=(c=='?')))
516 break;
517 case 3:
518 if (c==';' && npar<NPAR-1) {
519 npar++;
520 break;
521 } else if (c>='0' && c<='9') {
522 par[npar]=10*par[npar]+c-'0';
523 break;
524 } else state=4;
525 case 4:
526 state=0;
527 switch(c) {
528 case 'G': case '`':
529 if (par[0]) par[0]--;
530 gotoxy(par[0],y);
531 break;
532 case 'A':
533 if (!par[0]) par[0]++;
534 gotoxy(x,y-par[0]);
535 break;
536 case 'B': case 'e':
537 if (!par[0]) par[0]++;
538 gotoxy(x,y+par[0]);
539 break;
540 case 'C': case 'a':
541 if (!par[0]) par[0]++;
542 gotoxy(x+par[0],y);
543 break;
544 case 'D':
545 if (!par[0]) par[0]++;
546 gotoxy(x-par[0],y);
547 break;
548 case 'E':
549 if (!par[0]) par[0]++;
550 gotoxy(0,y+par[0]);
551 break;
552 case 'F':
553 if (!par[0]) par[0]++;
554 gotoxy(0,y-par[0]);
555 break;
556 case 'd':
557 if (par[0]) par[0]--;
558 gotoxy(x,par[0]);
559 break;
560 case 'H': case 'f':
561 if (par[0]) par[0]--;
562 if (par[1]) par[1]--;
563 gotoxy(par[1],par[0]);
564 break;
565 case 'J':
566 csi_J(par[0]);
567 break;
568 case 'K':
569 csi_K(par[0]);
570 break;
571 case 'L':
572 csi_L(par[0]);
573 break;
574 case 'M':
575 csi_M(par[0]);
576 break;
577 case 'P':
578 csi_P(par[0]);
579 break;
580 case '@':
581 csi_at(par[0]);
582 break;
583 case 'm':
584 csi_m();
585 break;
586 case 'r':
587 if (par[0]) par[0]--;
588 if (!par[1]) par[1] = video_num_lines;
589 if (par[0] < par[1] &&
590 par[1] <= video_num_lines) {
591 top=par[0];
592 bottom=par[1];
593 }
594 break;
595 case 's':
596 save_cur();
597 break;
598 case 'u':
599 restore_cur();
600 break;
601 }
602 }
603 }
604 set_cursor();
605}
606
607/*
608 * void con_init(void);
609 *
610 * This routine initalizes console interrupts, and does nothing
611 * else. If you want the screen to clear, call tty_write with
612 * the appropriate escape-sequece.
613 *
614 * Reads the information preserved by setup.s to determine the current display
615 * type and sets everything accordingly.
616 */
617void con_init(void)
618{
619 register unsigned char a;
620 char *display_desc = "????";
621 char *display_ptr;
622
623 video_num_columns = ORIG_VIDEO_COLS;
624 video_size_row = video_num_columns * 2;
625 video_num_lines = ORIG_VIDEO_LINES;
626 video_page = ORIG_VIDEO_PAGE;
627 video_erase_char = 0x0720;
628
629 if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
630 {
631 video_mem_start = 0xb0000;
632 video_port_reg = 0x3b4;
633 video_port_val = 0x3b5;
634 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
635 {
636 video_type = VIDEO_TYPE_EGAM;
637 video_mem_end = 0xb8000;
638 display_desc = "EGAm";
639 }
640 else
641 {
642 video_type = VIDEO_TYPE_MDA;
643 video_mem_end = 0xb2000;
644 display_desc = "*MDA";
645 }
646 }
647 else /* If not, it is color. */
648 {
649 video_mem_start = 0xb8000;
650 video_port_reg = 0x3d4;
651 video_port_val = 0x3d5;
652 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
653 {
654 video_type = VIDEO_TYPE_EGAC;
655 video_mem_end = 0xbc000;
656 display_desc = "EGAc";
657 }
658 else
659 {
660 video_type = VIDEO_TYPE_CGA;
661 video_mem_end = 0xba000;
662 display_desc = "*CGA";
663 }
664 }
665
666 /* Let the user known what kind of display driver we are using */
667
668 display_ptr = ((char *)video_mem_start) + video_size_row - 8;
669 while (*display_desc)
670 {
671 *display_ptr++ = *display_desc++;
672 display_ptr++;
673 }
674
675 /* Initialize the variables used for scrolling (mostly EGA/VGA) */
676
677 origin = video_mem_start;
678 scr_end = video_mem_start + video_num_lines * video_size_row;
679 top = 0;
680 bottom = video_num_lines;
681
682 gotoxy(ORIG_X,ORIG_Y);
683 set_trap_gate(0x21,&keyboard_interrupt);
684 outb_p(inb_p(0x21)&0xfd,0x21);
685 a=inb_p(0x61);
686 outb_p(a|0x80,0x61);
687 outb(a,0x61);
688}
689/* from bsd-net-2: */
690
691void sysbeepstop(void)
692{
693 /* disable counter 2 */
694 outb(inb_p(0x61)&0xFC, 0x61);
695}
696
697int beepcount = 0;
698
699static void sysbeep(void)
700{
701 /* enable counter 2 */
702 outb_p(inb_p(0x61)|3, 0x61);
703 /* set command for counter 2, 2 byte write */
704 outb_p(0xB6, 0x43);
705 /* send 0x637 for 750 HZ */
706 outb_p(0x37, 0x42);
707 outb(0x06, 0x42);
708 /* 1/8 second */
709 beepcount = HZ/8;
710}