root / Whitix / branches / hybrid / video / console.c

Revision 549, 14.2 kB (checked in by mwhitworth, 5 months ago)

Add earlyconsole driver.

Line 
1/*  This file is part of Whitix.
2 *
3 *  Whitix is free software; you can redistribute it and/or modify
4 *  it under the terms of the GNU General Public License as published by
5 *  the Free Software Foundation; either version 2 of the License, or
6 *  (at your option) any later version.
7 *
8 *  Whitix is distributed in the hope that it will be useful,
9 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 *  GNU General Public License for more details.
12 *
13 *  You should have received a copy of the GNU General Public License
14 *  along with Whitix; if not, write to the Free Software
15 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16 *
17 */
18
19#include <console.h>
20#include <fs/devfs.h>
21#include <fs/vfs.h>
22#include <init.h>
23#include <error.h>
24#include <malloc.h>
25#include <module.h>
26#include <i386/ioports.h>
27#include <task.h>
28
29/* Device number */
30#define CONSOLE_MAJOR 1
31
32/* Read settings from a kernel command line soon */
33
34#define CONSOLE_WIDTH   80
35#define CONSOLE_BWIDTH  (CONSOLE_WIDTH*2)
36#define CONSOLE_HEIGHT  25
37#define CONSOLE_BHEIGHT (CONSOLE_HEIGHT*2)
38#define CONSOLE_SIZE    (CONSOLE_WIDTH * CONSOLE_HEIGHT *2)     /* Console size in bytes. */
39#define TAB_WIDTH       8
40#define CLEAR           ((0x07 << 8) | (' '))
41
42#define CONSOLE_BUF(i)  (scrBuf+(CONSOLE_SIZE*(i)))
43#define CONSOLE_IND(i,j) ((j)*CONSOLE_BWIDTH + (i))
44
45/* == GLOBALS == */
46static int curX,curY;
47static BYTE* screen=(BYTE*)0xB8000; /* VGA memory. */
48static BYTE* scrBuf;
49int currConsole=0;
50struct Console consoles[MAX_CONSOLES];
51Spinlock consoleLock;
52
53static void ConsoleNewLine();
54static void ConsoleUpdateCursorPos();
55static void ConsoleClearScreen();
56static void ConsoleWrite(char c,int index);
57static int ConsoleWriteString(int console,char* str,int length);
58
59int ChangeConsole(int index)
60{
61        if (consoles[index].flags & CONSOLE_GRAPHICS || (currConsole == index))
62                return 0;
63
64        SpinLockIrq(&consoleLock);
65
66        /* Multiple screens are set up during the boot sequence. */
67        if (!scrBuf || index < 0 || index >= MAX_CONSOLES)
68                goto error;
69
70        /* Copy current vga screen memory to scrBuf[currConsole] */
71        memcpy(CONSOLE_BUF(currConsole),screen,CONSOLE_SIZE);
72        consoles[currConsole].currX=curX;
73        consoles[currConsole].currY=curY;
74
75        currConsole=index;
76
77        /* And copy scrBuf[currConsole] into VGA screen memory */
78        memcpy(screen,CONSOLE_BUF(currConsole), CONSOLE_SIZE);
79        curX=consoles[currConsole].currX;
80        curY=consoles[currConsole].currY;
81
82        ConsoleUpdateCursorPos();
83
84error:
85        SpinUnlockIrq(&consoleLock);
86        return 0;
87}
88
89SYMBOL_EXPORT(ChangeConsole);
90
91static void ConsoleScrollScreen(int index)
92{
93        int i;
94        DWORD flags;
95
96        if (consoles[index].flags & CONSOLE_GRAPHICS)
97                return ;
98
99        IrqSaveFlags(flags);
100 
101        if (currConsole == index)
102        {
103                for (i=0; i < CONSOLE_HEIGHT-1 ; i++)
104                        memcpy ( &screen [ CONSOLE_IND(0,i) ] , &screen [ CONSOLE_IND(0,i+1) ] , CONSOLE_BWIDTH);
105               
106                /* Clear the last line of the console. */
107                memsetw( & screen[ CONSOLE_IND(0,i) ] , CONSOLE_WIDTH, CLEAR);
108        }else{
109                for (i=0; i<CONSOLE_HEIGHT-1; i++)
110                        memcpy ( & CONSOLE_BUF(index) [ CONSOLE_IND(0,i) ] ,
111                                & CONSOLE_BUF(index) [ CONSOLE_IND(0,i) ], CONSOLE_BWIDTH);
112                       
113                /* Clear last line */
114                memsetw( & CONSOLE_BUF(index)[ CONSOLE_IND(0,i) ] , CONSOLE_WIDTH, CLEAR);
115        }
116
117        IrqRestoreFlags(flags);
118}
119
120void putc(int c)
121{
122        ConsoleWrite(c,currConsole);
123}
124
125unsigned char colorTable[] = {0, 4, 2, 6, 1, 5, 3, 7};
126
127int ConsoleWriteString(int console, char* str, int length)
128{
129        struct Console* currCons=&consoles[console];
130        DWORD flags;
131
132        if (currCons->flags & CONSOLE_GRAPHICS)
133                return 0;
134
135        IrqSaveFlags(flags);
136
137        while (length--)
138        {
139                if (*str == 0x1B)
140                {
141                        currCons->inCtrl=1;
142                        goto end;
143                }
144
145                if (currCons->inCtrl)
146                {
147                        if (*str == '[')
148                        {
149                                currCons->ctrlParams=1;
150                                ZeroMemory(currCons->params, sizeof(unsigned int)*16);
151                                currCons->paramIndex=0;
152                                goto end;
153                        }
154                       
155                        if (currCons->ctrlParams)
156                        {
157                                if (*str == ';')
158                                {
159                                        ++currCons->paramIndex;
160                                        goto end;
161                                }else if (*str < '0' || *str > '9') /* Command */
162                                {
163                                        currCons->cmdLetter=1;
164                                        currCons->ctrlParams=0;
165                                }else{
166                                        currCons->params[currCons->paramIndex]*=10;
167                                        currCons->params[currCons->paramIndex]+=(*str)-'0';
168                                        goto end;
169                                }
170                        }
171
172                        /* VT100 control characters are handled here. */
173                        if (currCons->cmdLetter)
174                        {
175                                switch (*str)
176                                {
177                                        /* 'J'. Clear the screen. */
178                                        case 'J':
179                                                ConsoleClearScreen(console);
180                                                break;
181
182                                        /* 'H'. Move the cursor to the specified position */
183                                        case 'H':
184
185                                                /* Bound the given parameters. */
186                                                if (currCons->params[0] >= CONSOLE_WIDTH)
187                                                        currCons->params[0]=CONSOLE_WIDTH;
188
189                                                if (currCons->params[1] >= CONSOLE_HEIGHT)
190                                                        currCons->params[1]=CONSOLE_HEIGHT;
191
192                                                /* Update the cursor position. */
193                                                if (currConsole == console)
194                                                {
195                                                        curX=currCons->params[0];
196                                                        curY=currCons->params[1];
197                                                        ConsoleUpdateCursorPos();
198                                                }else{
199                                                        currCons->currX=currCons->params[0];
200                                                        currCons->currY=currCons->params[1];
201                                                }
202
203                                                break;
204
205                                        /* 'K'. Erase characters from console. */
206                                        case 'K':
207                                        {
208                                                switch (currCons->params[0])
209                                                {
210
211                                                /* From current cursor position to end of line */
212                                                case 0:
213                                                        if (currConsole == console)
214                                                                memsetw((WORD*)(screen+(curY*(CONSOLE_WIDTH*2))+(curX*2)),CONSOLE_WIDTH-curX,(currCons->currColor << 8) | ' ');
215                                                        else
216                                                                memsetw((WORD*)(scrBuf+(CONSOLE_WIDTH*CONSOLE_HEIGHT*2*console)+(currCons->currY*(CONSOLE_WIDTH*2))+currCons->currX),CONSOLE_WIDTH-currCons->currX,(currCons->currColor << 8) | ' ');
217                                                        break;
218
219                                                /* From start of line to current cursor position */
220                                                case 1:
221                                                        if (currConsole == console)
222                                                                memsetw((WORD*)(screen+(curY*(CONSOLE_WIDTH*2))),curX,(currCons->currColor << 8) | ' ');
223                                                        else
224                                                                memsetw((WORD*)(scrBuf+(CONSOLE_WIDTH*CONSOLE_HEIGHT*2*console)+(currCons->currY*(CONSOLE_WIDTH*2))),curX,(currCons->currColor << 8) | ' ');
225                                                        break;
226
227                                                case 2:
228                                                        /* Erase whole of current line */
229                                                        if (currConsole == console)
230                                                                memsetw((WORD*)(screen+(curY*(CONSOLE_WIDTH*2))),CONSOLE_WIDTH,(currCons->currColor << 8) | ' ');
231                                                        else
232                                                                memsetw((WORD*)(scrBuf+(CONSOLE_WIDTH*CONSOLE_HEIGHT*2*console)+(currCons->currY*(CONSOLE_WIDTH*2))),CONSOLE_WIDTH,(currCons->currColor << 8) | ' ');
233                                                        break;
234                                                }
235                                                break;
236                                        }
237
238                                        /* 'm'. Set graphic rendition. */
239                                        case 'm':
240                                                switch (currCons->params[0])
241                                                {
242                                                        /* Reset the color */
243                                                        case 0:
244                                                                currCons->currColor=7;
245                                                                break;
246
247                                                        /* Invert the color */
248                                                        case 7:
249                                                                currCons->currColor=(currCons->currColor & 0x88) | (((currCons->currColor >> 4) | (currCons->currColor << 4)) & 0x77);                                                         
250                                                                break;
251
252                                                        case 30 ... 37:
253                                                                currCons->currColor=colorTable[currCons->params[0] % 10];
254                                                                break;
255                                                };
256
257                                                break;
258                                }
259
260                                currCons->inCtrl=currCons->cmdLetter=0;
261                                goto end;
262                        }
263                }
264
265                ConsoleWrite(*str,console);
266end:
267                str++;
268        }
269
270        IrqRestoreFlags(flags);
271
272        if (console == currConsole)
273                ConsoleUpdateCursorPos();
274
275        return 0;
276}
277
278SYMBOL_EXPORT(ConsoleWriteString);
279
280extern void KeyboardDoAlarm();
281
282/* Writes an ASCII character to screen */
283
284static void ConsoleWrite(char c,int index)
285{
286        struct Console* cons=&consoles[index];
287
288        if (cons->flags & CONSOLE_GRAPHICS)
289                return ;
290
291        switch (c)
292        {
293        case '\r':
294                break;
295
296        case '\n':
297                ConsoleNewLine(index);
298                break;
299       
300        case '\b':
301                if (currConsole == index && curX > 0)
302                {
303                        curX--;
304                        screen[(curY*(CONSOLE_WIDTH*2))+(curX*2)]=' ';
305                        screen[(curY*(CONSOLE_WIDTH*2))+(curX*2)+1]=cons->currColor;
306                }else if (cons->currX > 0)
307                {
308                        cons->currX--;
309                        scrBuf[(CONSOLE_WIDTH*CONSOLE_HEIGHT*2*index)+(cons->currY*(CONSOLE_WIDTH*2))+(cons->currX*2)]=' ';
310                        scrBuf[(CONSOLE_WIDTH*CONSOLE_HEIGHT*2*index)+(cons->currY*(CONSOLE_WIDTH*2))+(cons->currY*2)+1]=cons->currColor;
311                }
312                break;
313
314        case '\t':
315        {
316                if (currConsole == index)
317                {
318                        int i;
319                        for (i=0; i<TAB_WIDTH*2; i+=2)
320                        {
321                                screen[(curY*(CONSOLE_WIDTH*2))+(curX*2)+i]=' ';
322                                screen[(curY*(CONSOLE_WIDTH*2))+(curX*2)+1+i]=cons->currColor;
323                                ++curX;
324                                if (curX >= CONSOLE_WIDTH)
325                                        ConsoleNewLine(currConsole);
326                        }
327                }else{
328                        int i;
329                        for (i=0; i<TAB_WIDTH*2; i+=2)
330                        {
331                                scrBuf[(CONSOLE_WIDTH*CONSOLE_HEIGHT*2*index)+(cons->currY*(CONSOLE_WIDTH*2))+(cons->currX*2)+i]=' ';
332                                scrBuf[(CONSOLE_WIDTH*CONSOLE_HEIGHT*2*index)+(cons->currY*(CONSOLE_WIDTH*2))+(cons->currX*2)+i+1]=cons->currColor;
333                                ++cons->currX;
334                                if (cons->currX >= CONSOLE_WIDTH)
335                                        ConsoleNewLine(index);
336                        }
337                }
338                break;
339        }
340
341        default:
342                if (currConsole == index)
343                {
344                        screen[(curY*(CONSOLE_WIDTH*2))+(curX*2)]=c;
345                        screen[(curY*(CONSOLE_WIDTH*2))+(curX*2)+1]=cons->currColor;
346                        curX++;
347                        if (curX >= CONSOLE_WIDTH)
348                                ConsoleNewLine(currConsole);
349                }else{
350                        CONSOLE_BUF(index)[CONSOLE_IND(cons->currX*2, cons->currY)]=c;
351                        CONSOLE_BUF(index)[CONSOLE_IND(cons->currX*2, cons->currY)+1]=cons->currColor;
352                        ++cons->currX;
353                        if (cons->currX >= CONSOLE_WIDTH)
354                                ConsoleNewLine(index);
355                }
356        }
357}
358
359void ConsoleWriteOutput(char* message, int length)
360{
361        ConsoleWriteString(currConsole, message, length);
362}
363
364static void ConsoleClearScreen(int index)
365{
366        if (consoles[index].flags & CONSOLE_GRAPHICS)
367                return;
368
369        int i;
370        if (currConsole == index)
371        {
372                for (i=0; i<(CONSOLE_WIDTH*CONSOLE_HEIGHT*2); i+=2)
373                {
374                        screen[i]=' ';
375                        screen[i+1]=7;
376                }
377
378                curX=0;
379                curY=0;
380                ConsoleUpdateCursorPos();
381        }else{
382                for (i=0; i<(CONSOLE_WIDTH*CONSOLE_HEIGHT*2); i+=2)
383                {
384                        scrBuf[(CONSOLE_WIDTH*CONSOLE_HEIGHT*2*index)+i]=' ';
385                        scrBuf[(CONSOLE_WIDTH*CONSOLE_HEIGHT*2*index)+i+1]=7;
386                }
387
388                consoles[index].currX=0;
389                consoles[index].currY=0;
390        }
391}
392
393void ConsoleClearCurrent()
394{
395        ConsoleClearScreen(currConsole);
396}
397
398static void ConsoleUpdateCursorPos()
399{
400        DWORD flags;
401        WORD position;
402        IrqSaveFlags(flags);
403
404        position=(curY*(CONSOLE_WIDTH))+curX;
405
406        outb(0x3D4,14);
407        outb(0x3D5,(BYTE)(position >> 8));
408        outb(0x3D4,15);
409        outb(0x3D5,(BYTE)(position & 0xFF));
410
411        IrqRestoreFlags(flags);
412}
413
414static void ConsoleGetCursorPos()
415{
416        DWORD flags;
417        WORD position;
418
419        IrqSaveFlags(flags);
420
421        outb(0x3D4, 14);
422        position=inb(0x3D5) << 8;
423        outb(0x3D4, 15);
424        position |= inb(0x3D5);
425
426        IrqRestoreFlags(flags);
427
428        curX=position % 80;
429        curY=position/80;
430}
431
432static void ConsoleNewLine(int index)
433{
434        if (currConsole == index)
435        {
436                curX=0;
437                ++curY;
438                if (curY == CONSOLE_HEIGHT)
439                {
440                        curY=CONSOLE_HEIGHT-1;
441                        ConsoleScrollScreen(index);
442                }
443        }else{
444                consoles[index].currX=0;
445                ++consoles[index].currY;
446                if (consoles[index].currY == CONSOLE_HEIGHT)
447                {
448                        consoles[index].currY=CONSOLE_HEIGHT-1;
449                        ConsoleScrollScreen(index);
450                }
451        }
452}
453
454void ConsoleAddKey(BYTE n)
455{
456        BYTE head;
457        DWORD flags;
458        struct Console* currCons;
459
460        /* May not press keys before console array has been set up */
461        if (!scrBuf)
462                return;
463
464        currCons=&consoles[currConsole];
465
466        if (!currCons)
467                return;
468
469        if (!n)
470                return;
471
472        IrqSaveFlags(flags);
473
474        head=(currCons->head+1) % 25;
475        if (head != currCons->tail)
476        {
477                currCons->keyboardBuf[currCons->head]=n;
478                currCons->head=head;
479                WakeUp(&currCons->waitQueue);
480        }
481
482        IrqRestoreFlags(flags);
483}
484
485SYMBOL_EXPORT(ConsoleAddKey);
486
487void ConsoleAddKeyCode(BYTE key)
488{
489        if (consoles[currConsole].flags & CONSOLE_SENDKEYC)
490                ConsoleAddKey(key);
491}
492
493SYMBOL_EXPORT(ConsoleAddKeyCode);
494
495int ConsoleEarlyInit()
496{
497        ConsoleClearScreen(0);
498        consoles[0].currColor=7;
499        return 0;
500}
501
502BYTE ConsoleGetCharacter()
503{
504        BYTE retVal=0;
505        struct Console* currCons=&consoles[currConsole];
506
507        if (currCons->head != currCons->tail)
508        {
509                retVal=currCons->keyboardBuf[currCons->tail] & 0xFF;
510                currCons->tail=(currCons->tail+1) % 25; /* Wraps around */
511                if (!(currCons->flags & CONSOLE_NO_ECHO) && retVal < 0x80 && current && retVal != '\b') DoWriteFile(&current->files[0],&retVal,1);
512        }
513
514        return retVal;
515}
516
517int ConsoleDevRead(struct File* file,BYTE* data,DWORD size)
518{
519        int index=file->vNode->devId.minor;
520        struct Console* currCons=&consoles[index];
521        int i=0;
522        BYTE keyCode=0;
523        DWORD flags;
524
525//      printf("ConsoleDevRead %u, %d, %u %u\n", size, index, consoles[index].head, consoles[index].tail);
526
527        IrqSaveFlags(flags);
528
529        do
530        {
531                WAIT_ON(consoles[index].waitQueue, currCons->head != currCons->tail);
532
533                data[i++]=ConsoleGetCharacter();
534        }while (i < size);
535
536        IrqRestoreFlags(flags);
537
538        return size;
539}
540
541int ConsoleDevWrite(struct File* file,BYTE* data,DWORD size)
542{
543        return ConsoleWriteString(file->vNode->devId.minor,(char*)data,size);
544}
545
546int ConsoleDevSeek(struct File* file,int position,int whence)
547{
548        return -EINVAL;
549}
550
551int ConsoleIoCtl(struct File* file,unsigned long code,char* data)
552{
553        switch (code)
554        {
555        case CONSOLE_SET_OPTIONS:
556                consoles[file->vNode->devId.minor].flags=(int)data;
557                break;
558
559        case CONSOLE_GET_OPTIONS:
560                *(int*)data=consoles[file->vNode->devId.minor].flags;
561                break;
562
563        case CONSOLE_GET_INFO:
564        {
565                struct ConsoleInfo* info=(struct ConsoleInfo*)data; /* TODO: Check this is ok to access. */
566                info->rows=CONSOLE_HEIGHT;
567                info->cols=CONSOLE_WIDTH;
568                break;
569        }
570
571        default:
572                return -EINVAL;
573        }
574
575        return 0;
576}
577
578int ConsolePoll(struct File* file, struct PollItem* item, struct PollQueue* pollQueue)
579{
580        struct Console* cons=&consoles[file->vNode->devId.minor];
581
582        if (item->events & POLL_IN && cons->head != cons->tail)
583                item->revents |= POLL_IN;
584
585        if (item->events & POLL_OUT)
586                item->revents |= POLL_OUT;
587
588        PollAddWait(pollQueue, &cons->waitQueue);
589
590        return 0;
591}
592
593struct FileOps consoleOps={
594        .read = ConsoleDevRead, /* Read the keyboard buffer */
595        .write = ConsoleDevWrite,
596        .seek = ConsoleDevSeek,
597        .ioctl = ConsoleIoCtl,
598        .poll = ConsolePoll,
599};
600
601int ConsoleInit()
602{
603        int i;
604        char buf[32];
605
606        /* Now allocate all the other consoles, since dynamic memory allocation can be performed. */
607        scrBuf=(BYTE*)malloc(MAX_CONSOLES*(CONSOLE_WIDTH*CONSOLE_HEIGHT*2));
608        if (!scrBuf)
609        {
610                KernelPanic("Failed to allocate memory for multiple consoles");
611                return -ENOMEM; /* Never reached. */
612        }
613
614        ZeroMemory(scrBuf,(MAX_CONSOLES*(CONSOLE_WIDTH*CONSOLE_HEIGHT*2)));
615
616        /* Register all the consoles */
617        for (i=0; i<MAX_CONSOLES; i++)
618        {
619                sprintf(buf,"Consoles/Console%d",i);
620                DevAddDevice(buf,CONSOLE_MAJOR,i,DEVICE_CHAR,&consoleOps);
621                INIT_LIST_HEAD(&consoles[i].waitQueue.list);
622                consoles[i].currColor=7;
623                consoles[i].head=consoles[i].tail=0;
624        }
625
626        /* Get the current cursor position, and take over from the early console driver. */
627        ConsoleGetCursorPos();
628
629        KeSetOutput(ConsoleWriteOutput);
630
631        return 0;
632}
633
634DeviceInit(ConsoleInit);
Note: See TracBrowser for help on using the browser.