~galfy/helenos/bird-port-mainline

« back to all changes in this revision

Viewing changes to uspace/srv/fb/serial_console.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2006 Ondrej Palkovsky
 
3
 * Copyright (c) 2008 Martin Decky
 
4
 * Copyright (c) 2008 Pavel Rimsky
 
5
 * All rights reserved.
 
6
 *
 
7
 * Redistribution and use in source and binary forms, with or without
 
8
 * modification, are permitted provided that the following conditions
 
9
 * are met:
 
10
 *
 
11
 * - Redistributions of source code must retain the above copyright
 
12
 *   notice, this list of conditions and the following disclaimer.
 
13
 * - Redistributions in binary form must reproduce the above copyright
 
14
 *   notice, this list of conditions and the following disclaimer in the
 
15
 *   documentation and/or other materials provided with the distribution.
 
16
 * - The name of the author may not be used to endorse or promote products
 
17
 *   derived from this software without specific prior written permission.
 
18
 *
 
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
20
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
21
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
22
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
23
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
24
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
25
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
26
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
27
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
28
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
29
 */
 
30
 
 
31
/**
 
32
 * @defgroup serial Serial console
 
33
 * @brief    Serial console services (putc, puts, clear screen, cursor goto,...)
 
34
 * @{
 
35
 */ 
 
36
 
 
37
/** @file
 
38
 */
 
39
 
 
40
#include <stdio.h>
 
41
#include <ipc/ipc.h>
 
42
#include <async.h>
 
43
#include <ipc/fb.h>
 
44
#include <bool.h>
 
45
#include <errno.h>
 
46
#include <io/color.h>
 
47
#include <io/style.h>
 
48
#include <string.h>
 
49
 
 
50
#include "../console/screenbuffer.h"
 
51
#include "main.h"
 
52
#include "serial_console.h"
 
53
 
 
54
#define MAX_CONTROL 20
 
55
 
 
56
static void serial_sgr(const unsigned int mode);
 
57
void serial_putchar(wchar_t ch);
 
58
 
 
59
static int scr_width;
 
60
static int scr_height;
 
61
static bool color = true;       /** True if producing color output. */
 
62
static bool utf8 = false;       /** True if producing UTF8 output. */
 
63
static putc_function_t putc_function;
 
64
 
 
65
/* Allow only 1 connection */
 
66
static int client_connected = 0;
 
67
 
 
68
enum sgr_color_index {
 
69
        CI_BLACK        = 0,
 
70
        CI_RED          = 1,
 
71
        CI_GREEN        = 2,
 
72
        CI_BROWN        = 3,
 
73
        CI_BLUE         = 4,
 
74
        CI_MAGENTA      = 5,
 
75
        CI_CYAN         = 6,
 
76
        CI_WHITE        = 7,
 
77
};
 
78
 
 
79
enum sgr_command {
 
80
        SGR_RESET       = 0,
 
81
        SGR_BOLD        = 1,
 
82
        SGR_BLINK       = 5,
 
83
        SGR_REVERSE     = 7,
 
84
        SGR_NORMAL_INT  = 22,
 
85
        SGR_BLINK_OFF   = 25,
 
86
        SGR_REVERSE_OFF = 27,
 
87
        SGR_FGCOLOR     = 30,
 
88
        SGR_BGCOLOR     = 40
 
89
};
 
90
 
 
91
static int color_map[] = {
 
92
        [COLOR_BLACK]   = CI_BLACK,
 
93
        [COLOR_BLUE]    = CI_RED,
 
94
        [COLOR_GREEN]   = CI_GREEN,
 
95
        [COLOR_CYAN]    = CI_CYAN,
 
96
        [COLOR_RED]     = CI_RED,
 
97
        [COLOR_MAGENTA] = CI_MAGENTA,
 
98
        [COLOR_YELLOW]  = CI_BROWN,
 
99
        [COLOR_WHITE]   = CI_WHITE
 
100
};
 
101
 
 
102
void serial_puts(char *str)
 
103
{
 
104
        while (*str)
 
105
                putc_function(*(str++));
 
106
}
 
107
 
 
108
void serial_putchar(wchar_t ch)
 
109
{
 
110
        uint8_t buf[STR_BOUNDS(1)];
 
111
        size_t offs;
 
112
        size_t i;
 
113
 
 
114
        if (utf8 != true) {
 
115
                if (ch >= 0 && ch < 128)
 
116
                        (*putc_function)((uint8_t) ch);
 
117
                else 
 
118
                        (*putc_function)('?');
 
119
                return;
 
120
        }
 
121
 
 
122
        offs = 0;
 
123
        if (chr_encode(ch, buf, &offs, STR_BOUNDS(1)) == EOK) {
 
124
                for (i = 0; i < offs; i++)
 
125
                        (*putc_function)(buf[i]);
 
126
        } else {
 
127
                (*putc_function)('?');
 
128
        }
 
129
 
 
130
}
 
131
 
 
132
void serial_goto(const unsigned int col, const unsigned int row)
 
133
{
 
134
        if ((col > scr_width) || (row > scr_height))
 
135
                return;
 
136
        
 
137
        char control[MAX_CONTROL];
 
138
        snprintf(control, MAX_CONTROL, "\033[%u;%uf", row + 1, col + 1);
 
139
        serial_puts(control);
 
140
}
 
141
 
 
142
void serial_clrscr(void)
 
143
{
 
144
        /* Initialize graphic rendition attributes. */
 
145
        serial_sgr(SGR_RESET);
 
146
        if (color) {
 
147
                serial_sgr(SGR_FGCOLOR + CI_BLACK);
 
148
                serial_sgr(SGR_BGCOLOR + CI_WHITE);
 
149
        }
 
150
 
 
151
        serial_puts("\033[2J");
 
152
}
 
153
 
 
154
void serial_scroll(int i)
 
155
{
 
156
        if (i > 0) {
 
157
                serial_goto(0, scr_height - 1);
 
158
                while (i--)
 
159
                        serial_puts("\033D");
 
160
        } else if (i < 0) {
 
161
                serial_goto(0, 0);
 
162
                while (i++)
 
163
                        serial_puts("\033M");
 
164
        }
 
165
}
 
166
 
 
167
/** ECMA-48 Set Graphics Rendition. */
 
168
static void serial_sgr(const unsigned int mode)
 
169
{
 
170
        char control[MAX_CONTROL];
 
171
        snprintf(control, MAX_CONTROL, "\033[%um", mode);
 
172
        serial_puts(control);
 
173
}
 
174
 
 
175
/** Set scrolling region. */
 
176
void serial_set_scroll_region(unsigned last_row)
 
177
{
 
178
        char control[MAX_CONTROL];
 
179
        snprintf(control, MAX_CONTROL, "\033[0;%ur", last_row);
 
180
        serial_puts(control);
 
181
}
 
182
 
 
183
void serial_cursor_disable(void)
 
184
{
 
185
        serial_puts("\033[?25l");
 
186
}
 
187
 
 
188
void serial_cursor_enable(void)
 
189
{
 
190
        serial_puts("\033[?25h");
 
191
}
 
192
 
 
193
void serial_console_init(putc_function_t putc_fn, uint32_t w, uint32_t h)
 
194
{
 
195
        scr_width = w;
 
196
        scr_height = h;
 
197
        putc_function = putc_fn;
 
198
}
 
199
 
 
200
static void serial_set_style(int style)
 
201
{
 
202
        if (style == STYLE_EMPHASIS) {
 
203
                if (color) {
 
204
                        serial_sgr(SGR_RESET);
 
205
                        serial_sgr(SGR_FGCOLOR + CI_RED);
 
206
                        serial_sgr(SGR_BGCOLOR + CI_WHITE);
 
207
                }
 
208
                serial_sgr(SGR_BOLD);
 
209
        } else {
 
210
                if (color) {
 
211
                        serial_sgr(SGR_RESET);
 
212
                        serial_sgr(SGR_FGCOLOR + CI_BLACK);
 
213
                        serial_sgr(SGR_BGCOLOR + CI_WHITE);
 
214
                }
 
215
                serial_sgr(SGR_NORMAL_INT);
 
216
        }
 
217
}
 
218
 
 
219
static void serial_set_idx(unsigned fgcolor, unsigned bgcolor,
 
220
    unsigned flags)
 
221
{
 
222
        if (color) {
 
223
                serial_sgr(SGR_RESET);
 
224
                serial_sgr(SGR_FGCOLOR + color_map[fgcolor]);
 
225
                serial_sgr(SGR_BGCOLOR + color_map[bgcolor]);
 
226
        } else {
 
227
                if (fgcolor < bgcolor)
 
228
                        serial_sgr(SGR_RESET);
 
229
                else
 
230
                        serial_sgr(SGR_REVERSE);
 
231
        }       
 
232
}
 
233
 
 
234
static void serial_set_rgb(uint32_t fgcolor, uint32_t bgcolor)
 
235
{
 
236
        if (fgcolor < bgcolor)
 
237
                serial_sgr(SGR_REVERSE_OFF);
 
238
        else
 
239
                serial_sgr(SGR_REVERSE);
 
240
}
 
241
 
 
242
static void serial_set_attrs(const attrs_t *a)
 
243
{
 
244
        switch (a->t) {
 
245
        case at_style:
 
246
                serial_set_style(a->a.s.style);
 
247
                break;
 
248
        case at_rgb:
 
249
                serial_set_rgb(a->a.r.fg_color, a->a.r.bg_color);
 
250
                break;
 
251
        case at_idx:
 
252
                serial_set_idx(a->a.i.fg_color,
 
253
                    a->a.i.bg_color, a->a.i.flags);
 
254
                break;
 
255
        default:
 
256
                break;
 
257
        }
 
258
}
 
259
 
 
260
/** Draw text data to viewport.
 
261
 *
 
262
 * @param vport Viewport id
 
263
 * @param data  Text data.
 
264
 * @param x     Leftmost column of the area.
 
265
 * @param y     Topmost row of the area.
 
266
 * @param w     Number of rows.
 
267
 * @param h     Number of columns.
 
268
 */
 
269
static void draw_text_data(keyfield_t *data, unsigned int x,
 
270
    unsigned int y, unsigned int w, unsigned int h)
 
271
{
 
272
        unsigned int i, j;
 
273
        keyfield_t *field;
 
274
        attrs_t *a0, *a1;
 
275
 
 
276
        serial_goto(x, y);
 
277
        a0 = &data[0].attrs;
 
278
        serial_set_attrs(a0);
 
279
 
 
280
        for (j = 0; j < h; j++) {
 
281
                if (j > 0 && w != scr_width)
 
282
                        serial_goto(x, j);
 
283
 
 
284
                for (i = 0; i < w; i++) {
 
285
                        field = &data[j * w + i];
 
286
 
 
287
                        a1 = &field->attrs;
 
288
                        if (!attrs_same(*a0, *a1))
 
289
                                serial_set_attrs(a1);
 
290
                        serial_putchar(field->character);
 
291
                        a0 = a1;
 
292
                }
 
293
        }
 
294
}
 
295
 
 
296
int lastcol = 0;
 
297
int lastrow = 0;
 
298
 
 
299
/**
 
300
 * Main function of the thread serving client connections.
 
301
 */
 
302
void serial_client_connection(ipc_callid_t iid, ipc_call_t *icall)
 
303
{
 
304
        int retval;
 
305
        ipc_callid_t callid;
 
306
        ipc_call_t call;
 
307
        keyfield_t *interbuf = NULL;
 
308
        size_t intersize = 0;
 
309
 
 
310
        wchar_t c;
 
311
        int col, row, w, h;
 
312
        int i;
 
313
 
 
314
        attrs_t cur_attr;
 
315
        
 
316
        if (client_connected) {
 
317
                ipc_answer_0(iid, ELIMIT);
 
318
                return;
 
319
        }
 
320
        
 
321
        client_connected = 1;
 
322
        ipc_answer_0(iid, EOK);
 
323
 
 
324
        cur_attr.t = at_style;
 
325
        cur_attr.a.s.style = STYLE_NORMAL;
 
326
        
 
327
        /* Clear the terminal, set scrolling region
 
328
           to 0 - height rows. */
 
329
        serial_clrscr();
 
330
        serial_goto(0, 0);
 
331
        serial_set_scroll_region(scr_height);
 
332
        
 
333
        while (true) {
 
334
                callid = async_get_call(&call);
 
335
                switch (IPC_GET_METHOD(call)) {
 
336
                case IPC_M_PHONE_HUNGUP:
 
337
                        client_connected = 0;
 
338
                        ipc_answer_0(callid, EOK);
 
339
                        return;
 
340
                case IPC_M_SHARE_OUT:
 
341
                        /* We accept one area for data interchange */
 
342
                        intersize = IPC_GET_ARG2(call);
 
343
                        if (intersize >= scr_width * scr_height *
 
344
                            sizeof(*interbuf)) {
 
345
                                receive_comm_area(callid, &call,
 
346
                                    (void *) &interbuf);
 
347
                                continue;
 
348
                        }
 
349
                        retval = EINVAL;
 
350
                        break;
 
351
                case FB_DRAW_TEXT_DATA:
 
352
                        col = IPC_GET_ARG1(call);
 
353
                        row = IPC_GET_ARG2(call);
 
354
                        w = IPC_GET_ARG3(call);
 
355
                        h = IPC_GET_ARG4(call);
 
356
                        if (!interbuf) {
 
357
                                retval = EINVAL;
 
358
                                break;
 
359
                        }
 
360
                        if (col + w > scr_width || row + h > scr_height) {
 
361
                                retval = EINVAL;
 
362
                                break;
 
363
                        }
 
364
                        draw_text_data(interbuf, col, row, w, h);
 
365
                        lastcol = col + w;
 
366
                        lastrow = row + h - 1;
 
367
                        retval = 0;
 
368
                        break;
 
369
                case FB_PUTCHAR:
 
370
                        c = IPC_GET_ARG1(call);
 
371
                        col = IPC_GET_ARG2(call);
 
372
                        row = IPC_GET_ARG3(call);
 
373
                        if ((lastcol != col) || (lastrow != row))
 
374
                                serial_goto(col, row);
 
375
                        lastcol = col + 1;
 
376
                        lastrow = row;
 
377
                        serial_putchar(c);
 
378
                        retval = 0;
 
379
                        break;
 
380
                case FB_CURSOR_GOTO:
 
381
                        col = IPC_GET_ARG1(call);
 
382
                        row = IPC_GET_ARG2(call);
 
383
                        serial_goto(col, row);
 
384
                        lastcol = col;
 
385
                        lastrow = row;
 
386
                        retval = 0;
 
387
                        break;
 
388
                case FB_GET_CSIZE:
 
389
                        ipc_answer_2(callid, EOK, scr_width, scr_height);
 
390
                        continue;
 
391
                case FB_GET_COLOR_CAP:
 
392
                        ipc_answer_1(callid, EOK, color ? FB_CCAP_INDEXED :
 
393
                            FB_CCAP_STYLE);
 
394
                        continue;
 
395
                case FB_CLEAR:
 
396
                        serial_clrscr();
 
397
                        retval = 0;
 
398
                        break;
 
399
                case FB_SET_STYLE:
 
400
                        cur_attr.t = at_style;
 
401
                        cur_attr.a.s.style = IPC_GET_ARG1(call);
 
402
                        cur_attr.a.i.bg_color = IPC_GET_ARG2(call);
 
403
                        serial_set_attrs(&cur_attr);
 
404
 
 
405
                        retval = 0;
 
406
                        break;
 
407
                case FB_SET_COLOR:
 
408
                        cur_attr.t = at_idx;
 
409
                        cur_attr.a.i.fg_color = IPC_GET_ARG1(call);
 
410
                        cur_attr.a.i.bg_color = IPC_GET_ARG2(call);
 
411
                        cur_attr.a.i.flags = IPC_GET_ARG3(call);
 
412
                        serial_set_attrs(&cur_attr);
 
413
 
 
414
                        retval = 0;
 
415
                        break;
 
416
                case FB_SET_RGB_COLOR:
 
417
                        cur_attr.t = at_rgb;
 
418
                        cur_attr.a.i.fg_color = IPC_GET_ARG1(call);
 
419
                        cur_attr.a.i.bg_color = IPC_GET_ARG2(call);
 
420
                        serial_set_attrs(&cur_attr);
 
421
 
 
422
                        retval = 0;
 
423
                        break;
 
424
                case FB_SCROLL:
 
425
                        i = IPC_GET_ARG1(call);
 
426
                        if ((i > scr_height) || (i < -scr_height)) {
 
427
                                retval = EINVAL;
 
428
                                break;
 
429
                        }
 
430
                        serial_scroll(i);
 
431
                        serial_goto(lastcol, lastrow);
 
432
                        retval = 0;
 
433
                        break;
 
434
                case FB_CURSOR_VISIBILITY:
 
435
                        if(IPC_GET_ARG1(call))
 
436
                                serial_cursor_enable();
 
437
                        else
 
438
                                serial_cursor_disable();
 
439
                        retval = 0;
 
440
                        break;
 
441
                case FB_SCREEN_YIELD:
 
442
                        serial_sgr(SGR_RESET);
 
443
                        serial_puts("\033[2J");
 
444
                        serial_goto(0, 0);
 
445
                        serial_cursor_enable();
 
446
                        retval = 0;
 
447
                        break;
 
448
                case FB_SCREEN_RECLAIM:
 
449
                        serial_clrscr();
 
450
                        serial_set_attrs(&cur_attr);
 
451
                        retval = 0;
 
452
                        break;
 
453
                default:
 
454
                        retval = ENOENT;
 
455
                }
 
456
                ipc_answer_0(callid, retval);
 
457
        }
 
458
}
 
459
 
 
460
/**
 
461
 * @}
 
462
 */