|
|
1.1 root 1: /*
2: * console.c
3: *
4: * This module implements the console io functions
5: * 'void con_init(void)'
6: * 'void con_write(struct tty_queue * queue)'
7: * Hopefully this will be a rather complete VT102 implementation.
8: *
9: */
10:
11: /*
12: * NOTE!!! We sometimes disable and enable interrupts for a short while
13: * (to put a word in video IO), but this will work even for keyboard
14: * interrupts. We know interrupts aren't enabled when getting a keyboard
15: * interrupt, as we use trap-gates. Hopefully all is well.
16: */
17:
18: #include <linux/sched.h>
19: #include <linux/tty.h>
20: #include <asm/io.h>
21: #include <asm/system.h>
22:
23: #define SCREEN_START 0xb8000
24: #define SCREEN_END 0xc0000
25: #define LINES 25
26: #define COLUMNS 80
27: #define NPAR 16
28:
29: extern void keyboard_interrupt(void);
30:
31: static unsigned long origin=SCREEN_START;
32: static unsigned long scr_end=SCREEN_START+LINES*COLUMNS*2;
33: static unsigned long pos;
34: static unsigned long x,y;
35: static unsigned long top=0,bottom=LINES;
36: static unsigned long lines=LINES,columns=COLUMNS;
37: static unsigned long state=0;
38: static unsigned long npar,par[NPAR];
39: static unsigned long ques=0;
40: static unsigned char attr=0x07;
41:
42: /*
43: * this is what the terminal answers to a ESC-Z or csi0c
44: * query (= vt100 response).
45: */
46: #define RESPONSE "\033[?1;2c"
47:
48: static inline void gotoxy(unsigned int new_x,unsigned int new_y)
49: {
50: if (new_x>=columns || new_y>=lines)
51: return;
52: x=new_x;
53: y=new_y;
54: pos=origin+((y*columns+x)<<1);
55: }
56:
57: static inline void set_origin(void)
58: {
59: cli();
60: outb_p(12,0x3d4);
61: outb_p(0xff&((origin-SCREEN_START)>>9),0x3d5);
62: outb_p(13,0x3d4);
63: outb_p(0xff&((origin-SCREEN_START)>>1),0x3d5);
64: sti();
65: }
66:
67: static void scrup(void)
68: {
69: if (!top && bottom==lines) {
70: origin += columns<<1;
71: pos += columns<<1;
72: scr_end += columns<<1;
73: if (scr_end>SCREEN_END) {
1.1.1.2 ! root 74:
! 75: int d0,d1,d2,d3;
! 76: __asm__ __volatile("cld\n\t"
1.1 root 77: "rep\n\t"
78: "movsl\n\t"
1.1.1.2 ! root 79: "movl columns,%1\n\t"
1.1 root 80: "rep\n\t"
81: "stosw"
1.1.1.2 ! root 82: :"=&a" (d0), "=&c" (d1), "=&D" (d2), "=&S" (d3)
! 83: :"0" (0x0720),
! 84: "1" ((lines-1)*columns>>1),
! 85: "2" (SCREEN_START),
! 86: "3" (origin)
! 87: :"memory");
! 88:
1.1 root 89: scr_end -= origin-SCREEN_START;
90: pos -= origin-SCREEN_START;
91: origin = SCREEN_START;
92: } else {
1.1.1.2 ! root 93: int d0,d1,d2;
! 94: __asm__ __volatile("cld\n\t"
1.1 root 95: "rep\n\t"
96: "stosl"
1.1.1.2 ! root 97: :"=&a" (d0), "=&c" (d1), "=&D" (d2)
! 98: :"0" (0x07200720),
! 99: "1" (columns>>1),
! 100: "2" (scr_end-(columns<<1))
! 101: :"memory");
1.1 root 102: }
103: set_origin();
104: } else {
1.1.1.2 ! root 105: int d0,d1,d2,d3;
! 106: __asm__ __volatile__("cld\n\t"
1.1 root 107: "rep\n\t"
108: "movsl\n\t"
1.1.1.2 ! root 109: "movl columns,%%ecx\n\t"
1.1 root 110: "rep\n\t"
111: "stosw"
1.1.1.2 ! root 112: :"=&a" (d0), "=&c" (d1), "=&D" (d2), "=&S" (d3)
! 113: :"0" (0x0720),
! 114: "1" ((bottom-top-1)*columns>>1),
! 115: "2" (origin+(columns<<1)*top),
! 116: "3" (origin+(columns<<1)*(top+1))
! 117: :"memory");
1.1 root 118: }
119: }
120:
121: static void scrdown(void)
122: {
1.1.1.2 ! root 123: int d0,d1,d2,d3;
! 124: __asm__ __volatile__("std\n\t"
1.1 root 125: "rep\n\t"
126: "movsl\n\t"
127: "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
1.1.1.2 ! root 128: "movl columns,%%ecx\n\t"
1.1 root 129: "rep\n\t"
130: "stosw"
1.1.1.2 ! root 131: :"=&a" (d0), "=&c" (d1), "=&D" (d2), "=&S" (d3)
! 132: :"0" (0x0720),
! 133: "1" ((bottom-top-1)*columns>>1),
! 134: "2" (origin+(columns<<1)*bottom-4),
! 135: "3" (origin+(columns<<1)*(bottom-1)-4)
! 136: :"memory");
1.1 root 137: }
138:
139: static void lf(void)
140: {
141: if (y+1<bottom) {
142: y++;
143: pos += columns<<1;
144: return;
145: }
146: scrup();
147: }
148:
149: static void ri(void)
150: {
151: if (y>top) {
152: y--;
153: pos -= columns<<1;
154: return;
155: }
156: scrdown();
157: }
158:
159: static void cr(void)
160: {
161: pos -= x<<1;
162: x=0;
163: }
164:
165: static void del(void)
166: {
167: if (x) {
168: pos -= 2;
169: x--;
170: *(unsigned short *)pos = 0x0720;
171: }
172: }
173:
174: static void csi_J(int par)
175: {
1.1.1.2 ! root 176: long count;
! 177: long start;
1.1 root 178:
179: switch (par) {
180: case 0: /* erase from cursor to end of display */
181: count = (scr_end-pos)>>1;
182: start = pos;
183: break;
184: case 1: /* erase from start to cursor */
185: count = (pos-origin)>>1;
186: start = origin;
187: break;
188: case 2: /* erase whole display */
189: count = columns*lines;
190: start = origin;
191: break;
192: default:
193: return;
194: }
1.1.1.2 ! root 195: int d0,d1,d2;
! 196: __asm__ __volatile__("cld\n\t"
1.1 root 197: "rep\n\t"
198: "stosw\n\t"
1.1.1.2 ! root 199: :"=&c" (d0), "=&D" (d1), "=&a" (d2)
! 200: :"0" (count),"1" (start),"2" (0x0720)
! 201: :"memory");
1.1 root 202: }
203:
204: static void csi_K(int par)
205: {
1.1.1.2 ! root 206: long count;
! 207: long start;
1.1 root 208:
209: switch (par) {
210: case 0: /* erase from cursor to end of line */
211: if (x>=columns)
212: return;
213: count = columns-x;
214: start = pos;
215: break;
216: case 1: /* erase from start of line to cursor */
217: start = pos - (x<<1);
218: count = (x<columns)?x:columns;
219: break;
220: case 2: /* erase whole line */
221: start = pos - (x<<1);
222: count = columns;
223: break;
224: default:
225: return;
226: }
1.1.1.2 ! root 227: int d0,d1,d2;
! 228: __asm__ __volatile__("cld\n\t"
1.1 root 229: "rep\n\t"
230: "stosw\n\t"
1.1.1.2 ! root 231: :"=&c" (d0), "=&D" (d1), "=&a" (d2)
! 232: :"0" (count),"1" (start),"2" (0x0720)
! 233: :"memory");
1.1 root 234: }
235:
236: void csi_m(void)
237: {
238: int i;
239:
240: for (i=0;i<=npar;i++)
241: switch (par[i]) {
242: case 0:attr=0x07;break;
243: case 1:attr=0x0f;break;
244: case 4:attr=0x0f;break;
245: case 7:attr=0x70;break;
246: case 27:attr=0x07;break;
247: }
248: }
249:
250: static inline void set_cursor(void)
251: {
252: cli();
253: outb_p(14,0x3d4);
254: outb_p(0xff&((pos-SCREEN_START)>>9),0x3d5);
255: outb_p(15,0x3d4);
256: outb_p(0xff&((pos-SCREEN_START)>>1),0x3d5);
257: sti();
258: }
259:
260: static void respond(struct tty_struct * tty)
261: {
262: char * p = RESPONSE;
263:
264: cli();
265: while (*p) {
266: PUTCH(*p,tty->read_q);
267: p++;
268: }
269: sti();
270: copy_to_cooked(tty);
271: }
272:
273: static void insert_char(void)
274: {
275: int i=x;
276: unsigned short tmp,old=0x0720;
277: unsigned short * p = (unsigned short *) pos;
278:
279: while (i++<columns) {
280: tmp=*p;
281: *p=old;
282: old=tmp;
283: p++;
284: }
285: }
286:
287: static void insert_line(void)
288: {
289: int oldtop,oldbottom;
290:
291: oldtop=top;
292: oldbottom=bottom;
293: top=y;
294: bottom=lines;
295: scrdown();
296: top=oldtop;
297: bottom=oldbottom;
298: }
299:
300: static void delete_char(void)
301: {
302: int i;
303: unsigned short * p = (unsigned short *) pos;
304:
305: if (x>=columns)
306: return;
307: i = x;
308: while (++i < columns) {
309: *p = *(p+1);
310: p++;
311: }
312: *p=0x0720;
313: }
314:
315: static void delete_line(void)
316: {
317: int oldtop,oldbottom;
318:
319: oldtop=top;
320: oldbottom=bottom;
321: top=y;
322: bottom=lines;
323: scrup();
324: top=oldtop;
325: bottom=oldbottom;
326: }
327:
328: static void csi_at(int nr)
329: {
330: if (nr>columns)
331: nr=columns;
332: else if (!nr)
333: nr=1;
334: while (nr--)
335: insert_char();
336: }
337:
338: static void csi_L(int nr)
339: {
340: if (nr>lines)
341: nr=lines;
342: else if (!nr)
343: nr=1;
344: while (nr--)
345: insert_line();
346: }
347:
348: static void csi_P(int nr)
349: {
350: if (nr>columns)
351: nr=columns;
352: else if (!nr)
353: nr=1;
354: while (nr--)
355: delete_char();
356: }
357:
358: static void csi_M(int nr)
359: {
360: if (nr>lines)
361: nr=lines;
362: else if (!nr)
363: nr=1;
364: while (nr--)
365: delete_line();
366: }
367:
368: static int saved_x=0;
369: static int saved_y=0;
370:
371: static void save_cur(void)
372: {
373: saved_x=x;
374: saved_y=y;
375: }
376:
377: static void restore_cur(void)
378: {
379: x=saved_x;
380: y=saved_y;
381: pos=origin+((y*columns+x)<<1);
382: }
383:
384: void con_write(struct tty_struct * tty)
385: {
386: int nr;
387: char c;
388:
389: nr = CHARS(tty->write_q);
390: while (nr--) {
391: GETCH(tty->write_q,c);
392: switch(state) {
393: case 0:
394: if (c>31 && c<127) {
395: if (x>=columns) {
396: x -= columns;
397: pos -= columns<<1;
398: lf();
399: }
1.1.1.2 ! root 400: __asm__("movb attr,%%ah\n\t"
1.1 root 401: "movw %%ax,%1\n\t"
402: ::"a" (c),"m" (*(short *)pos)
1.1.1.2 ! root 403: /*:"ax"*/);
1.1 root 404: pos += 2;
405: x++;
406: } else if (c==27)
407: state=1;
408: else if (c==10 || c==11 || c==12)
409: lf();
410: else if (c==13)
411: cr();
412: else if (c==ERASE_CHAR(tty))
413: del();
414: else if (c==8) {
415: if (x) {
416: x--;
417: pos -= 2;
418: }
419: } else if (c==9) {
420: c=8-(x&7);
421: x += c;
422: pos += c<<1;
423: if (x>columns) {
424: x -= columns;
425: pos -= columns<<1;
426: lf();
427: }
428: c=9;
429: }
430: break;
431: case 1:
432: state=0;
433: if (c=='[')
434: state=2;
435: else if (c=='E')
436: gotoxy(0,y+1);
437: else if (c=='M')
438: ri();
439: else if (c=='D')
440: lf();
441: else if (c=='Z')
442: respond(tty);
443: else if (x=='7')
444: save_cur();
445: else if (x=='8')
446: restore_cur();
447: break;
448: case 2:
449: for(npar=0;npar<NPAR;npar++)
450: par[npar]=0;
451: npar=0;
452: state=3;
1.1.1.2 ! root 453: if ((ques=(c=='?')))
1.1 root 454: break;
455: case 3:
456: if (c==';' && npar<NPAR-1) {
457: npar++;
458: break;
459: } else if (c>='0' && c<='9') {
460: par[npar]=10*par[npar]+c-'0';
461: break;
462: } else state=4;
463: case 4:
464: state=0;
465: switch(c) {
466: case 'G': case '`':
467: if (par[0]) par[0]--;
468: gotoxy(par[0],y);
469: break;
470: case 'A':
471: if (!par[0]) par[0]++;
472: gotoxy(x,y-par[0]);
473: break;
474: case 'B': case 'e':
475: if (!par[0]) par[0]++;
476: gotoxy(x,y+par[0]);
477: break;
478: case 'C': case 'a':
479: if (!par[0]) par[0]++;
480: gotoxy(x+par[0],y);
481: break;
482: case 'D':
483: if (!par[0]) par[0]++;
484: gotoxy(x-par[0],y);
485: break;
486: case 'E':
487: if (!par[0]) par[0]++;
488: gotoxy(0,y+par[0]);
489: break;
490: case 'F':
491: if (!par[0]) par[0]++;
492: gotoxy(0,y-par[0]);
493: break;
494: case 'd':
495: if (par[0]) par[0]--;
496: gotoxy(x,par[0]);
497: break;
498: case 'H': case 'f':
499: if (par[0]) par[0]--;
500: if (par[1]) par[1]--;
501: gotoxy(par[1],par[0]);
502: break;
503: case 'J':
504: csi_J(par[0]);
505: break;
506: case 'K':
507: csi_K(par[0]);
508: break;
509: case 'L':
510: csi_L(par[0]);
511: break;
512: case 'M':
513: csi_M(par[0]);
514: break;
515: case 'P':
516: csi_P(par[0]);
517: break;
518: case '@':
519: csi_at(par[0]);
520: break;
521: case 'm':
522: csi_m();
523: break;
524: case 'r':
525: if (par[0]) par[0]--;
526: if (!par[1]) par[1]=lines;
527: if (par[0] < par[1] &&
528: par[1] <= lines) {
529: top=par[0];
530: bottom=par[1];
531: }
532: break;
533: case 's':
534: save_cur();
535: break;
536: case 'u':
537: restore_cur();
538: break;
539: }
540: }
541: }
542: set_cursor();
543: }
544:
545: /*
546: * void con_init(void);
547: *
548: * This routine initalizes console interrupts, and does nothing
549: * else. If you want the screen to clear, call tty_write with
550: * the appropriate escape-sequece.
551: */
552: void con_init(void)
553: {
554: register unsigned char a;
555:
556: gotoxy(*(unsigned char *)(0x90000+510),*(unsigned char *)(0x90000+511));
557: set_trap_gate(0x21,&keyboard_interrupt);
558: outb_p(inb_p(0x21)&0xfd,0x21);
559: a=inb_p(0x61);
560: outb_p(a|0x80,0x61);
561: outb(a,0x61);
562: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.