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