Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / bsp / drv / dev / base / wscons.c @ 03e9c04a

History | View | Annotate | Download (10.5 KB)

1
/*-
2
 * Copyright (c) 2005-2009, Kohsuke Ohtani
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. Neither the name of the author nor the names of any co-contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29

    
30
/*
31
 * wscons.c - "Workstation console" multiplexor driver.
32
 */
33

    
34
#include <driver.h>
35
#include <cons.h>
36
#include <tty.h>
37
#include <wscons.h>
38

    
39
/* #define DEBUG_WSCONS 1 */
40

    
41
#ifdef DEBUG_WSCONS
42
#define DPRINTF(a) printf a
43
#else
44
#define DPRINTF(a)
45
#endif
46

    
47
struct esc_state {
48
        int                index;
49
        int                arg1;
50
        int                arg2;
51
        int                argc;
52
        int                saved_col;
53
        int                saved_row;
54
};
55

    
56
struct wscons_softc {
57
        device_t        dev;                /* our device */
58
        struct tty        tty;                /* associated tty */
59
        int                row;                /* current row */
60
        int                col;                /* current col */
61
        int                nrows;                /* number of rows */
62
        int                ncols;                /* number of cols */
63
        int                attr;                /* current attribute */
64
        struct esc_state esc;                /* escape state */
65
        struct wscons_video_ops *vid_ops; /* video operations */
66
        struct wscons_kbd_ops   *kbd_ops; /* keyboard operations */
67
        void                *vid_aux;        /* video private data */
68
        void                *kbd_aux;        /* keyboard private data */
69
};
70

    
71
static int        wscons_init(struct driver *);
72
static int        wscons_read(device_t, char *, size_t *, int);
73
static int        wscons_write(device_t, char *, size_t *, int);
74
static int        wscons_ioctl(device_t, u_long, void *);
75

    
76
static int        wscons_cngetc(device_t);
77
static void        wscons_cnputc(device_t, int);
78
static void        wscons_cnpollc(device_t, int);
79

    
80

    
81
static struct devops wscons_devops = {
82
        /* open */        no_open,
83
        /* close */        no_close,
84
        /* read */        wscons_read,
85
        /* write */        wscons_write,
86
        /* ioctl */        wscons_ioctl,
87
        /* devctl */        no_devctl,
88
};
89

    
90
struct driver wscons_driver = {
91
        /* name */        "wscons",
92
        /* devops */        &wscons_devops,
93
        /* devsz */        sizeof(struct wscons_softc),
94
        /* flags */        0,
95
        /* probe */        NULL,
96
        /* init */        wscons_init,
97
        /* unload */        NULL,
98
};
99

    
100
static struct consdev wsconsdev = {
101
        /* dev */        NODEV,
102
        /* devops */        &wscons_devops,
103
        /* cngetc */        wscons_cngetc,
104
        /* cnputc */        wscons_cnputc,
105
        /* cnpollc */        wscons_cnpollc,
106
};
107

    
108
static const u_short ansi_colors[] = {0, 4, 2, 6, 1, 5, 3, 7};
109

    
110
/*
111
 * Pointer to the wscons state. There can be only one instance.
112
 */
113
static struct wscons_softc *wscons_softc;
114

    
115

    
116
static int
117
wscons_read(device_t dev, char *buf, size_t *nbyte, int blkno)
118
{
119
        struct tty *tty = &wscons_softc->tty;
120

    
121
        return tty_read(tty, buf, nbyte);
122
}
123

    
124
static int
125
wscons_write(device_t dev, char *buf, size_t *nbyte, int blkno)
126
{
127
        struct tty *tty = &wscons_softc->tty;
128

    
129
        return tty_write(tty, buf, nbyte);
130
}
131

    
132
static int
133
wscons_ioctl(device_t dev, u_long cmd, void *arg)
134
{
135
        struct tty *tty = &wscons_softc->tty;
136

    
137
        return tty_ioctl(tty, cmd, arg);
138
}
139

    
140
static void
141
wscons_move_cursor(struct wscons_softc *sc)
142
{
143
        struct wscons_video_ops *vops = sc->vid_ops;
144

    
145
        vops->cursor(sc->vid_aux, sc->row, sc->col);
146
}
147

    
148
static void
149
wscons_set_attr(struct wscons_softc *sc)
150
{
151
        struct wscons_video_ops *vops = sc->vid_ops;
152

    
153
        vops->set_attr(sc->vid_aux, sc->attr);
154
}
155

    
156
static void
157
wscons_clear(struct wscons_softc *sc)
158
{
159
        struct wscons_video_ops *vops = sc->vid_ops;
160

    
161
        vops->eraserows(sc->vid_aux, 0, sc->nrows);
162
        sc->col = 0;
163
        sc->row = 0;
164
        wscons_move_cursor(sc);
165
}
166

    
167
static void
168
wscons_scrollup(struct wscons_softc *sc)
169
{
170
        struct wscons_video_ops *vops = sc->vid_ops;
171

    
172
        vops->copyrows(sc->vid_aux, 1, 0, sc->nrows - 1);
173
        vops->eraserows(sc->vid_aux, sc->nrows - 1, 1);
174
}
175

    
176
static void
177
wscons_newline(struct wscons_softc *sc)
178
{
179

    
180
        sc->col = 0;
181
        sc->row++;
182
        if (sc->row >= sc->nrows) {
183
                sc->row = sc->nrows - 1;
184
                wscons_scrollup(sc);
185
        }
186
}
187

    
188
/*
189
 * Check for escape code sequence.
190
 * Rreturn true if escape
191
 *
192
 * <Support list>
193
 *  ESC[#;#H or        : moves cursor to line #, column #
194
 *  ESC[#;#f
195
 *  ESC[#A        : moves cursor up # lines
196
 *  ESC[#B        : moves cursor down # lines
197
 *  ESC[#C        : moves cursor right # spaces
198
 *  ESC[#D        : moves cursor left # spaces
199
 *  ESC[#;#R        : reports current cursor line & column
200
 *  ESC[s        : save cursor position for recall later
201
 *  ESC[u        : return to saved cursor position
202
 *  ESC[2J        : clear screen and home cursor
203
 *  ESC[K        : clear to end of line
204
 *  ESC[#m        : attribute (0=attribure off, 4=underline, 5=blink)
205
 */
206
static int
207
wscons_check_escape(struct wscons_softc *sc, char c)
208
{
209
        struct esc_state *esc = &sc->esc;
210
        int move = 0;
211
        int val;
212
        u_short color;
213

    
214
        if (c == 033) {
215
                esc->index = 1;
216
                esc->argc = 0;
217
                return 1;
218
        }
219
        if (esc->index == 0)
220
                return 0;
221

    
222
        if (c >= '0' && c <= '9') {
223
                val = c - '0';
224
                switch (esc->argc) {
225
                case 0:
226
                        esc->arg1 = val;
227
                        esc->index++;
228
                        break;
229
                case 1:
230
                        esc->arg1 = esc->arg1 * 10 + val;
231
                        break;
232
                case 2:
233
                        esc->arg2 = val;
234
                        esc->index++;
235
                        break;
236
                case 3:
237
                        esc->arg2 = esc->arg2 * 10 + val;
238
                        break;
239
                default:
240
                        goto reset;
241
                }
242
                esc->argc++;
243
                return 1;
244
        }
245

    
246
        esc->index++;
247

    
248
        switch (esc->index) {
249
        case 2:
250
                if (c != '[')
251
                        goto reset;
252
                return 1;
253
        case 3:
254
                switch (c) {
255
                case 's':        /* Save cursor position */
256
                        esc->saved_col = sc->col;
257
                        esc->saved_row = sc->row;
258
                        printf("TTY: save %d %d\n", sc->col, sc->row);
259
                        break;
260
                case 'u':        /* Return to saved cursor position */
261
                        sc->col = esc->saved_col;
262
                        sc->row = esc->saved_row;
263
                        printf("TTY: restore %d %d\n", sc->col, sc->row);
264
                        wscons_move_cursor(sc);
265
                        break;
266
                case 'K':        /* Clear to end of line */
267
                        break;
268
                }
269
                goto reset;
270
        case 4:
271
                switch (c) {
272
                case 'A':        /* Move cursor up # lines */
273
                        sc->row -= esc->arg1;
274
                        if (sc->row < 0)
275
                                sc->row = 0;
276
                        move = 1;
277
                        break;
278
                case 'B':        /* Move cursor down # lines */
279
                        sc->row += esc->arg1;
280
                        if (sc->row >= sc->nrows)
281
                                sc->row = sc->nrows - 1;
282
                        move = 1;
283
                        break;
284
                case 'C':        /* Move cursor forward # spaces */
285
                        sc->col += esc->arg1;
286
                        if (sc->col >= sc->ncols)
287
                                sc->col = sc->ncols - 1;
288
                        move = 1;
289
                        break;
290
                case 'D':        /* Move cursor back # spaces */
291
                        sc->col -= esc->arg1;
292
                        if (sc->col < 0)
293
                                sc->col = 0;
294
                        move = 1;
295
                        break;
296
                case ';':
297
                        if (esc->argc == 1)
298
                                esc->argc = 2;
299
                        return 1;
300
                case 'J':
301
                        if (esc->arg1 == 2)        /* Clear screen */
302
                                wscons_clear(sc);
303
                        break;
304
                case 'm':        /* Change attribute */
305
                        switch (esc->arg1) {
306
                        case 0:                /* reset */
307
                                sc->attr = 0x0F;
308
                                break;
309
                        case 1:                /* bold */
310
                                sc->attr = 0x0F;
311
                                break;
312
                        case 4:                /* under line */
313
                                break;
314
                        case 5:                /* blink */
315
                                sc->attr |= 0x80;
316
                                break;
317
                        case 30: case 31: case 32: case 33:
318
                        case 34: case 35: case 36: case 37:
319
                                color = ansi_colors[esc->arg1 - 30];
320
                                sc->attr = (sc->attr & 0xf0) | color;
321
                                break;
322
                        case 40: case 41: case 42: case 43:
323
                        case 44: case 45: case 46: case 47:
324
                                color = ansi_colors[esc->arg1 - 40];
325
                                sc->attr = (sc->attr & 0x0f) | (color << 4);
326
                                break;
327
                        }
328
                        wscons_set_attr(sc);
329
                        break;
330

    
331
                }
332
                if (move)
333
                        wscons_move_cursor(sc);
334
                goto reset;
335
        case 6:
336
                switch (c) {
337
                case 'H':        /* Cursor position */
338
                case 'f':
339
                        sc->row = esc->arg1;
340
                        sc->col = esc->arg2;
341
                        if (sc->row >= sc->nrows)
342
                                sc->row = sc->nrows - 1;
343
                        if (sc->col >= sc->ncols)
344
                                sc->col = sc->ncols - 1;
345
                        wscons_move_cursor(sc);
346
                        break;
347
                case 'R':
348
                        /* XXX */
349
                        break;
350
                }
351
                goto reset;
352
        default:
353
                goto reset;
354
        }
355
        /* NOTREACHED */
356
 reset:
357
        esc->index = 0;
358
        esc->argc = 0;
359
        return 1;
360
}
361

    
362
static void
363
wscons_putc(int c)
364
{
365
        struct wscons_softc *sc = wscons_softc;
366
        struct wscons_video_ops *vops = sc->vid_ops;
367

    
368
        if (wscons_check_escape(sc, c))
369
                return;
370

    
371
        switch (c) {
372
        case '\n':
373
                wscons_newline(sc);
374
                return;
375
        case '\r':
376
                sc->col = 0;
377
                return;
378
        case '\b':
379
                if (sc->col == 0)
380
                        return;
381
                sc->col--;
382
                return;
383
        }
384

    
385
        vops->putc(sc->vid_aux, sc->row, sc->col, c);
386

    
387
        sc->col++;
388
        if (sc->col >= sc->ncols) {
389
                sc->col = 0;
390
                sc->row++;
391
                if (sc->row >= sc->nrows) {
392
                        sc->row = sc->nrows - 1;
393
                        wscons_scrollup(sc);
394
                }
395
        }
396
}
397

    
398
/*
399
 * Start output operation.
400
 */
401
static void
402
wscons_start(struct tty *tp)
403
{
404
        struct wscons_softc *sc = wscons_softc;
405
        int c;
406

    
407
        while ((c = tty_getc(&tp->t_outq)) >= 0)
408
                wscons_putc(c);
409

    
410
        wscons_move_cursor(sc);
411
        tty_done(tp);
412
}
413

    
414
static int
415
wscons_cngetc(device_t dev)
416
{
417
        struct wscons_softc *sc = wscons_softc;
418
        struct wscons_kbd_ops *kops = sc->kbd_ops;
419

    
420
        return kops->getc(sc->kbd_aux);
421
}
422

    
423
static void
424
wscons_cnputc(device_t dev, int c)
425
{
426
        struct wscons_softc *sc = wscons_softc;
427

    
428
        wscons_putc(c);
429
        wscons_move_cursor(sc);
430
}
431

    
432
static void
433
wscons_cnpollc(device_t dev, int on)
434
{
435
        struct wscons_softc *sc = wscons_softc;
436
        struct wscons_kbd_ops *kops = sc->kbd_ops;
437

    
438
        kops->set_poll(sc->kbd_aux, on);
439
}
440

    
441
void
442
wscons_kbd_input(int c)
443
{
444
        struct wscons_softc *sc = wscons_softc;
445

    
446
        tty_input(c, &sc->tty);
447
}
448

    
449
void
450
wscons_attach_video(struct wscons_video_ops *ops, void *aux)
451
{
452
        struct wscons_softc *sc = wscons_softc;
453
        int diag = 0;
454

    
455
        sc->vid_ops = ops;
456
        sc->vid_aux = aux;
457
        ops->get_cursor(aux, &sc->col, &sc->row);
458

    
459
#ifdef CONFIG_DIAG_SCREEN
460
        diag = 1;
461
#endif
462
        wsconsdev.dev = sc->dev;
463
        cons_attach(&wsconsdev, diag);
464
}
465

    
466
void
467
wscons_attach_kbd(struct wscons_kbd_ops *ops, void *aux)
468
{
469
        struct wscons_softc *sc = wscons_softc;
470

    
471
        sc->kbd_ops = ops;
472
        sc->kbd_aux = aux;
473
}
474

    
475
static int
476
wscons_init(struct driver *self)
477
{
478
        struct bootinfo *bi;
479
        struct wscons_softc *sc;
480
        device_t dev;
481

    
482
        dev = device_create(self, "tty", D_CHR|D_TTY);
483

    
484
        sc = device_private(dev);
485
        sc->dev = dev;
486
        sc->esc.index = 0;
487
        sc->attr = 0x0f;
488
        wscons_softc = sc;
489

    
490
        tty_attach(&sc->tty);
491
        sc->tty.t_dev = dev;
492
        sc->tty.t_oproc = wscons_start;
493

    
494
        machine_bootinfo(&bi);
495
        sc->nrows = bi->video.text_y;
496
        sc->ncols = bi->video.text_x;
497
        return 0;
498
}