source: trunk/kernel/drivers/ibmpc/tty.c @ 26

Last change on this file since 26 was 4, checked in by alain, 8 years ago

Introduce the chdev_t structure in place of device_t.

File size: 11.1 KB
Line 
1/*
2 * tty.c - a basic tty driver
3 *
4 * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless
5 * Copyright (c) 2011,2012 UPMC Sorbonne Universites
6 *
7 * This file is part of ALMOS-kernel.
8 *
9 * ALMOS-kernel is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2.0 of the License.
12 *
13 * ALMOS-kernel is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with ALMOS-kernel; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <config.h>
24#include <system.h>
25#include <cpu.h>
26#include <chdev.h>
27#include <driver.h>
28#include <cpu-io.h>
29#include <kmem.h>
30#include <libk.h>
31#include <tty.h>
32#include <rwlock.h>
33#include <cpu-trace.h>
34#include <thread.h>
35#include <mwmr.h>
36
37struct device_s ttys_tbl[TTY_DEV_NR];
38
39static void tty_clear(struct device_s *tty)
40{
41        register uint_t i = 0;
42        struct tty_context_s *ctx;
43        uint8_t *vga_ram;
44
45        ctx = (struct tty_context_s*)tty->data;
46        vga_ram = (uint8_t*)tty->base;
47
48        for(i = 0; i < TTY_SIZE; i+=2)
49        {
50                vga_ram[i] = 0;
51                vga_ram[i+1] = ctx->attr;
52        }
53}
54
55
56static sint_t tty_read(struct device_s *tty, dev_request_t *rq)
57{
58        struct tty_context_s *ctx; 
59        register size_t size;
60        uint_t irq_state;
61        register char *dst;
62        register size_t count;
63        register uint32_t eol = 0;
64   
65        cpu_trace_write(CURRENT_THREAD->local_cpu, tty_read);
66
67        ctx = (struct tty_context_s*)tty->data;
68        size = 0;
69        count = rq->count;
70        dst = rq->dst;
71   
72        if(rq->flags & DEV_RQ_NOBLOCK)
73                rwlock_rdlock(&ctx->rwlock);
74        else
75                rwlock_wrlock(&ctx->rwlock);
76
77        spinlock_lock_noirq(&tty->lock, &irq_state);
78
79        size = mwmr_read(ctx->in_channel, dst, count);
80        eol = ctx->eol;
81   
82        if((eol) || (size == count) || (rq->flags & DEV_RQ_NOBLOCK))
83        {
84                ctx->eol = 0;
85                spinlock_unlock_noirq(&tty->lock, irq_state);
86                rwlock_unlock(&ctx->rwlock);
87                return size;
88        }
89
90        rq->count -= size;
91        rq->dst = dst + size;
92        ctx->pending_rq = rq;
93
94        wait_on(&ctx->wait_queue, WAIT_LAST);
95        spinlock_unlock_noirq(&tty->lock, irq_state);
96        sched_sleep(CURRENT_THREAD);
97        rwlock_unlock(&ctx->rwlock);
98        return count - rq->count;
99}
100
101void tty_scrollup(struct device_s *tty, int n)
102{
103        struct tty_context_s *ctx;
104        uint8_t *vga_ram;
105        uint8_t *ptr;
106        uint8_t *limit = (uint8_t*)((uint_t)TTY_SIZE);
107
108        ctx = (struct tty_context_s*)tty->data;
109        vga_ram = (uint8_t*)tty->base;
110
111        for(; vga_ram < limit; vga_ram+=2)
112        {
113                ptr=&vga_ram[n*2*TTY_XSIZE];
114   
115                if(ptr < limit) 
116                {
117                        *vga_ram = *ptr;
118                        *(vga_ram + 1) = *(ptr+1);
119                }
120                else
121                {
122                        *vga_ram = 0;
123                        *(vga_ram+1) = 0x07;
124                }
125        }
126 
127        ctx->pos_Y -= n;
128        ctx->pos_Y = (ctx->pos_Y < 0) ? 0 : ctx->pos_Y;
129}
130
131static void tty_cleanup(struct device_s *tty)
132{
133        struct tty_context_s *ctx;
134
135        ctx = (struct tty_context_s*)tty->data;
136        tty_clear(tty);
137        ctx->pos_Y = 0;
138        ctx->pos_X = 0;
139}
140
141#define TTY_CURSOR_CMD        0x3d4
142#define TTY_CURSOR_DATA       0x3d5
143
144void tty_move_cursor(uint_t pos_X, uint_t pos_Y)
145{
146        uint_t pos;
147
148        pos = pos_Y * TTY_XSIZE + pos_X;
149        cpu_io_out8(TTY_CURSOR_CMD, 0x0f);
150        cpu_io_out8(TTY_CURSOR_DATA, pos);
151        cpu_io_out8(TTY_CURSOR_CMD, 0x0e);
152        cpu_io_out8(TTY_CURSOR_DATA, pos >> 8);
153}
154
155static void tty_putc(struct device_s *tty, uint8_t ch)
156{
157        struct tty_context_s *ctx;
158        uint8_t *vga_ram;
159        int offset;
160
161        ctx = (struct tty_context_s*)tty->data;
162        vga_ram = (uint8_t*)tty->base;
163
164        switch (ch)
165        {
166        case '\b':
167                ctx->pos_X --;
168                break;
169        case '\t':
170                ctx->pos_X += 8;
171                break;
172
173        case '\r':
174                ctx->pos_X = 0;
175                break;
176
177        case '\n':     
178                ctx->pos_X = 0;
179                ctx->pos_Y ++;
180                break;
181 
182        default:
183                offset = 2*TTY_XSIZE*ctx->pos_Y + 2*ctx->pos_X;
184                ctx->pos_X++;
185                vga_ram[offset] = ch;
186                vga_ram[offset + 1] = (uint8_t)(ctx->attr & 0xFF);
187        }
188
189        if(ctx->pos_X >= TTY_XSIZE)
190        {
191                ctx->pos_X = 0;
192                ctx->pos_Y ++;
193        }
194 
195#if 1
196        if(ctx->pos_Y >= TTY_YSIZE)
197        {
198                tty_cleanup(tty);
199                //ctx->pos_Y = 0;
200        }
201#endif
202}
203
204
205static sint_t tty_write(struct device_s *tty, dev_request_t *rq)
206{
207        struct tty_context_s *ctx; 
208        register unsigned int i;
209        register size_t size = rq->count;
210 
211        cpu_trace_write(CURRENT_THREAD->local_cpu, tty_write);
212 
213        ctx = (struct tty_context_s*)tty->data;
214 
215        if(!(rq->flags & DEV_RQ_NOBLOCK))
216                rwlock_wrlock(&ctx->rwlock);
217
218        for (i = 0; i < size; i++)
219                tty_putc(tty, *((uint8_t*)rq->src + i));
220
221        if(!(rq->flags & DEV_RQ_NOBLOCK))
222                rwlock_unlock(&ctx->rwlock);
223
224        return size;
225}
226
227
228static sint_t tty_get_params(struct device_s *tty, dev_params_t *params)
229{
230        params->chr.xSize = TTY_XSIZE;
231        params->chr.ySize = TTY_YSIZE;
232        params->size = 0;
233        return 0;
234}
235
236#define KEYBOARD_READ_REG     0x60
237#define KEYBOARD_WRITE_REG    0x60
238#define KEYBOARD_STATUS_REG   0x64
239#define KEYBORAD_CMD_REG      0x64
240
241#define KEY_IS_HOLD           0x80
242#define KEY_IS_LEFT_SHIFT     0x29
243#define KEY_IS_RIGHT_SHIFT    0x35
244#define KEY_IS_ALT            0x37
245#define KEY_IS_CTRL           0x1C
246#define KEY_IS_CAPSLOCK       0x39
247
248static uint_t isLeftShift;
249static uint_t isRightShift;
250static uint_t isAlt;
251static uint_t isCtrl;
252static uint_t isCAPSLOCK;
253
254static error_t tty_getc(struct device_s *tty)
255{
256        register uint8_t isUpper;
257        register uint8_t scode;
258        register error_t ch;
259        ch = -1;
260        scode = 0;
261
262        /* Waite KEYBOARD OUTPUT BUFFER */
263        do
264        {
265                scode = cpu_io_in8(KEYBOARD_STATUS_REG);
266        }while((scode & 0x1) == 0);
267   
268        scode = cpu_io_in8(KEYBOARD_READ_REG);
269        scode --;
270 
271        //  isr_dmsg(DEBUG, "scode %x\n", scode);
272 
273        if(scode < KEY_IS_HOLD)
274        {
275                switch (scode)
276                {
277                case KEY_IS_RIGHT_SHIFT:
278                        isRightShift = 1;
279                        break;
280                case KEY_IS_CTRL:
281                        isCtrl = 1;
282                        break;
283                case KEY_IS_ALT:
284                        isAlt = 1;
285                        break;
286                case KEY_IS_CAPSLOCK:
287                        break;
288                case KEY_IS_LEFT_SHIFT:
289                        isLeftShift = 1;
290                        break;
291                default:
292                        isUpper = (isRightShift || isLeftShift || isCAPSLOCK) ? 1 : 0;
293                        ch = keyboard_map[(scode << 2) + isUpper + isAlt];
294                }
295        }
296        else
297        {
298                scode -= 0x80;
299                switch (scode)
300                {
301                case KEY_IS_RIGHT_SHIFT:
302                        isRightShift = 0;
303                        break;
304                case KEY_IS_CTRL:
305                        isCtrl = 0;
306                        break;
307                case KEY_IS_ALT:
308                        isAlt = 0;
309                        break;
310                case KEY_IS_CAPSLOCK:
311                        isCAPSLOCK = (isCAPSLOCK) ? 0 : 1;
312                        break;
313                case KEY_IS_LEFT_SHIFT:
314                        isLeftShift = 0;
315                        break;
316                default:
317                        /* No action for other scan code */
318                        break;
319                }
320        }
321 
322        struct tty_context_s *ctx = tty->data;
323        tty_move_cursor(ctx->pos_X, ctx->pos_Y);
324        return ch;
325}
326
327static void tty_irq_handler(struct irq_action_s *action)
328{
329        sint_t ch;
330        struct device_s *tty;
331        struct tty_context_s *ctx; 
332        register char *dst;
333        volatile uint32_t *base;
334   
335        cpu_trace_write(CURRENT_THREAD->local_cpu, tty_irq_handler);
336
337        tty = action->dev;
338        base = tty->base;
339        ctx = (struct tty_context_s*)tty->data;
340
341        if((ch = tty_getc(tty)) & 0x80)
342                return;
343
344        cpu_spinlock_lock(&tty->lock.val);
345
346        if(ctx->pending_rq != NULL)
347        {
348                dst = ctx->pending_rq->dst;
349                *(dst ++) = ch;
350                ctx->pending_rq->dst = dst;
351                ctx->pending_rq->count --;
352
353                if((ch == '\n') || (ctx->pending_rq->count == 0))
354                {
355                        wakeup_one(&ctx->wait_queue, WAIT_FIRST);
356                        ctx->pending_rq = NULL;
357                }
358        }
359        else
360        {
361                mwmr_write(ctx->in_channel, &ch, 1);
362                if(ch == '\n') ctx->eol = 1;
363        }
364
365#if CONFIG_TTY_ECHO_MODE
366        switch(ch)
367        {
368        case '\b':
369        case 0x7F:
370                tty_putc(tty, '\b');
371        tty_putc(tty, ' ');
372        tty_putc(tty, '\b');
373        break;
374        default:
375                tty_putc(tty, ch);
376        }
377#endif
378
379        cpu_spinlock_unlock(&tty->lock.val);
380}
381
382void ibmpc_tty_init(struct device_s *tty, void *base, uint_t irq, uint_t tty_id)
383{
384        struct tty_context_s *ctx;
385 
386        isRightShift = 0;
387        isLeftShift = 0;
388        isCtrl = 0;
389        isAlt = 0;
390        isCAPSLOCK = 0;
391
392        spinlock_init(&tty->lock);
393        tty->base = base;
394        tty->irq = irq;
395        tty->type = DEV_CHR;
396
397        tty->action.dev = tty;
398        tty->action.irq_handler = &tty_irq_handler;
399        tty->action.data = NULL;
400 
401        tty->op.dev.open = NULL;
402        tty->op.dev.read = &tty_read;
403        tty->op.dev.write = &tty_write;
404        tty->op.dev.close = NULL;
405        tty->op.dev.lseek = NULL;
406        tty->op.dev.set_params = NULL;
407        tty->op.dev.get_params = &tty_get_params;
408
409        ctx = kbootMem_calloc(sizeof(*ctx));
410        ctx->id = tty_id;
411        ctx->in_channel = mwmr_init(1,TTY_BUFFER_DEPTH, 0);
412        rwlock_init(&ctx->rwlock);
413        ctx->eol = 0;
414        ctx->attr = 0x07;
415        tty->data = (void*) ctx;
416        sprintk(tty->name, "TTY%d", tty_id);
417        metafs_init(&tty->node, tty->name);
418        wait_queue_init(&ctx->wait_queue,tty->name);
419        tty_clear(tty);
420}
421
422
423uint8_t keyboard_map[] = { 0x1B, 0x1B, 0x1B, 0x1B,
424                           '&', '1', '1', '1',
425                           '~', '2', '2', '2',
426                           '"', '3', '3', '3',
427                           '\'','4', '{', '{',
428                           '(', '5', '5', '5',
429                           '-', '6', '|', '|',
430                           '`', '7', '7', '7',
431                           '_', '8', '\\', '\\',
432                           '^', '9', '9', '9',
433                           '@', '0', '0', '0',
434                           ')', ']', '-', '-',
435                           '=', '+', '}','}',
436                           '\b','\b', 0x7F,'\b',
437                           '\t','\t','\t','\t',
438                           'a', 'A', 'a', 'a',
439                           'z', 'Z', 'z', 'z',
440                           'e', 'E', 'e', 'e',
441                           'r', 'R', 'r', 'r',
442                           't', 'T', 't', 't',
443                           'y', 'Y', 'y', 'y',
444                           'u', 'U', 'u', 'u',
445                           'i', 'I', 'i', 'i',
446                           'o', 'O', 'o', 'o',
447                           'p', 'P', 'p', 'p',
448                           '[', '{', '[', '[',
449                           '$', '$', '$', ']',
450                           '\n','\n','\n','\n',
451                           0xFF, 0xFF, 0xFF, 0xFF,
452                           'q', 'A', 'a', 'a',
453                           's', 'S', 's', 's',
454                           'd', 'D', 'd', 'd',
455                           'f', 'F', 'f', 'f',
456                           'g', 'G', 'g', 'g',
457                           'h', 'H', 'h', 'h',
458                           'j', 'J', 'j', 'j',
459                           'k', 'K', 'k', 'k',
460                           'l', 'L', 'l', 'l',
461                           'm', 'M', ';', ';',
462                           '%', '%', '%', '%',
463                           0x28, 0x28, 0x28, 0x28,
464                           0x29, 0x29, 0x29, 0x29, /* Left Shift (41) */
465                           '*', '*', '*', '*',
466                           'w', 'W', 'w', 'w',
467                           'x', 'X', 'x', 'x',
468                           'c', 'C', 'c', 'c',
469                           'v', 'V', 'v', 'v',
470                           'b', 'B', 'b', 'b',
471                           'n', 'N', 'n', 'n',
472                           ',', '?', ',', ',',
473                           ';', '.', ';', ';',
474                           ':', '/', ':', ':',
475                           '!', '!', '!', '!',
476                           0x35, 0x35, 0x35, 0x35,      /*      Rshift  (0x35)  */
477                           0xFF, 0xFF, 0xFF, 0xFF,     
478                           0xFF, 0xFF, 0xFF, 0xFF,     
479                           ' ', ' ', ' ', ' ',          /*      space   */
480                           0x39, 0x39, 0x39, 0x39,     
481                           0xFF, 0xFF, 0xFF, 0xFF,     
482                           0xFF, 0xFF, 0xFF, 0xFF,     
483                           0xFF, 0xFF, 0xFF, 0xFF,     
484                           0xFF, 0xFF, 0xFF, 0xFF,     
485                           0xFF, 0xFF, 0xFF, 0xFF,     
486                           0xFF, 0xFF, 0xFF, 0xFF,     
487                           0xFF, 0xFF, 0xFF, 0xFF, /* 0x40 */   
488                           0xFF, 0xFF, 0xFF, 0xFF, 
489                           0xFF, 0xFF, 0xFF, 0xFF,     
490                           0xFF, 0xFF, 0xFF, 0xFF,     
491                           0xFF, 0xFF, 0xFF, 0xFF,     
492                           0xFF, 0xFF, 0xFF, 0xFF,     
493                           0xFF, 0xFF, 0xFF, 0xFF,     
494                           0xFF, 0xFF, 0xFF, 0xFF,     
495                           0xFF, 0xFF, 0xFF, 0xFF,     
496                           0xFF, 0xFF, 0xFF, 0xFF,     
497                           0xFF, 0xFF, 0xFF, 0xFF,     
498                           0xFF, 0xFF, 0xFF, 0xFF,     
499                           0xFF, 0xFF, 0xFF, 0xFF,     
500                           0xFF, 0xFF, 0xFF, 0xFF,     
501                           0xFF, 0xFF, 0xFF, 0xFF,     
502                           0xFF, 0xFF, 0xFF, 0xFF,     
503                           0xFF, 0xFF, 0xFF, 0xFF, /* 0x50 */
504                           0xFF, 0xFF, 0xFF, 0xFF,     
505                           0xFF, 0xFF, 0xFF, 0xFF,     
506                           0xFF, 0xFF, 0xFF, 0xFF,     
507                           0xFF, 0xFF, 0xFF, 0xFF,     
508                           '<', '>', '<', '<',
509                           0xFF, 0xFF, 0xFF, 0xFF,     
510                           0xFF, 0xFF, 0xFF, 0xFF,     
511                           0xFF, 0xFF, 0xFF, 0xFF,     
512                           0xFF, 0xFF, 0xFF, 0xFF,     
513                           0xFF, 0xFF, 0xFF, 0xFF,     
514                           0xFF, 0xFF, 0xFF, 0xFF,     
515                           0xFF, 0xFF, 0xFF, 0xFF,     
516                           0xFF, 0xFF, 0xFF, 0xFF,     
517                           0xFF, 0xFF, 0xFF, 0xFF,     
518                           0xFF, 0xFF, 0xFF, 0xFF,     
519                           0xFF, 0xFF, 0xFF, 0xFF, /* 0x60 */
520                           0xFF, 0xFF, 0xFF, 0xFF};
Note: See TracBrowser for help on using the repository browser.