source: mainline/uspace/srv/hid/fb/serial_console.c@ 53e197f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 53e197f was 53e197f, checked in by Martin Decky <martin@…>, 15 years ago

fix attributes on serial console

  • Property mode set to 100644
File size: 10.6 KB
Line 
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 <str.h>
49#include <io/screenbuffer.h>
50
51#include "main.h"
52#include "serial_console.h"
53
54#define MAX_CONTROL 20
55
56static ipcarg_t scr_width;
57static ipcarg_t scr_height;
58static bool color = true; /**< True if producing color output. */
59static bool utf8 = false; /**< True if producing UTF8 output. */
60static putc_function_t putc_function;
61
62static ipcarg_t lastcol = 0;
63static ipcarg_t lastrow = 0;
64static attrs_t cur_attr = {
65 .t = at_style,
66 .a.s.style = STYLE_NORMAL
67};
68
69/* Allow only 1 connection */
70static int client_connected = 0;
71
72enum sgr_color_index {
73 CI_BLACK = 0,
74 CI_RED = 1,
75 CI_GREEN = 2,
76 CI_BROWN = 3,
77 CI_BLUE = 4,
78 CI_MAGENTA = 5,
79 CI_CYAN = 6,
80 CI_WHITE = 7
81};
82
83enum sgr_command {
84 SGR_RESET = 0,
85 SGR_BOLD = 1,
86 SGR_BLINK = 5,
87 SGR_REVERSE = 7,
88 SGR_NORMAL_INT = 22,
89 SGR_BLINK_OFF = 25,
90 SGR_REVERSE_OFF = 27,
91 SGR_FGCOLOR = 30,
92 SGR_BGCOLOR = 40
93};
94
95static int color_map[] = {
96 [COLOR_BLACK] = CI_BLACK,
97 [COLOR_BLUE] = CI_RED,
98 [COLOR_GREEN] = CI_GREEN,
99 [COLOR_CYAN] = CI_CYAN,
100 [COLOR_RED] = CI_RED,
101 [COLOR_MAGENTA] = CI_MAGENTA,
102 [COLOR_YELLOW] = CI_BROWN,
103 [COLOR_WHITE] = CI_WHITE
104};
105
106void serial_puts(const char *str)
107{
108 while (*str)
109 putc_function(*(str++));
110}
111
112static void serial_putchar(wchar_t ch)
113{
114 if (utf8 != true) {
115 if (ch >= 0 && ch < 128)
116 (*putc_function)((uint8_t) ch);
117 else
118 (*putc_function)('?');
119
120 return;
121 }
122
123 size_t offs = 0;
124 char buf[STR_BOUNDS(1)];
125 if (chr_encode(ch, buf, &offs, STR_BOUNDS(1)) == EOK) {
126 size_t i;
127 for (i = 0; i < offs; i++)
128 (*putc_function)(buf[i]);
129 } else
130 (*putc_function)('?');
131}
132
133void serial_goto(const ipcarg_t col, const ipcarg_t row)
134{
135 if ((col > scr_width) || (row > scr_height))
136 return;
137
138 char control[MAX_CONTROL];
139 snprintf(control, MAX_CONTROL, "\033[%u;%uf", row + 1, col + 1);
140 serial_puts(control);
141}
142
143/** ECMA-48 Set Graphics Rendition. */
144static void serial_sgr(const unsigned int mode)
145{
146 char control[MAX_CONTROL];
147 snprintf(control, MAX_CONTROL, "\033[%um", mode);
148 serial_puts(control);
149}
150
151static void serial_set_style(console_style_t style)
152{
153 switch (style) {
154 case STYLE_EMPHASIS:
155 if (color) {
156 serial_sgr(SGR_RESET);
157 serial_sgr(SGR_FGCOLOR + CI_RED);
158 serial_sgr(SGR_BGCOLOR + CI_WHITE);
159 }
160 serial_sgr(SGR_BOLD);
161 break;
162 case STYLE_INVERTED:
163 if (color) {
164 serial_sgr(SGR_RESET);
165 serial_sgr(SGR_FGCOLOR + CI_WHITE);
166 serial_sgr(SGR_BGCOLOR + CI_BLACK);
167 serial_sgr(SGR_NORMAL_INT);
168 } else
169 serial_sgr(SGR_REVERSE);
170 break;
171 case STYLE_SELECTED:
172 if (color) {
173 serial_sgr(SGR_RESET);
174 serial_sgr(SGR_FGCOLOR + CI_WHITE);
175 serial_sgr(SGR_BGCOLOR + CI_RED);
176 serial_sgr(SGR_NORMAL_INT);
177 } else {
178 serial_sgr(SGR_BOLD);
179 serial_sgr(SGR_REVERSE);
180 }
181 break;
182 default:
183 if (color) {
184 serial_sgr(SGR_RESET);
185 serial_sgr(SGR_FGCOLOR + CI_BLACK);
186 serial_sgr(SGR_BGCOLOR + CI_WHITE);
187 }
188 serial_sgr(SGR_NORMAL_INT);
189 }
190}
191
192static void serial_set_idx(uint8_t fgcolor, uint8_t bgcolor,
193 uint8_t flags)
194{
195 if (color) {
196 serial_sgr(SGR_RESET);
197 serial_sgr(SGR_FGCOLOR + color_map[fgcolor]);
198 serial_sgr(SGR_BGCOLOR + color_map[bgcolor]);
199 } else {
200 if (fgcolor < bgcolor)
201 serial_sgr(SGR_RESET);
202 else
203 serial_sgr(SGR_REVERSE);
204 }
205}
206
207static void serial_set_rgb(uint32_t fgcolor, uint32_t bgcolor)
208{
209 serial_sgr(SGR_RESET);
210
211 if (fgcolor < bgcolor)
212 serial_sgr(SGR_REVERSE_OFF);
213 else
214 serial_sgr(SGR_REVERSE);
215}
216
217static void serial_set_attrs(attrs_t *a)
218{
219 switch (a->t) {
220 case at_style:
221 serial_set_style(a->a.s.style);
222 break;
223 case at_rgb:
224 serial_set_rgb(a->a.r.fg_color, a->a.r.bg_color);
225 break;
226 case at_idx:
227 serial_set_idx(a->a.i.fg_color, a->a.i.bg_color,
228 a->a.i.flags);
229 break;
230 }
231}
232
233void serial_clrscr(void)
234{
235 /* Initialize graphic rendition attributes. */
236 serial_sgr(SGR_RESET);
237 if (color) {
238 serial_sgr(SGR_FGCOLOR + CI_BLACK);
239 serial_sgr(SGR_BGCOLOR + CI_WHITE);
240 }
241
242 serial_puts("\033[2J");
243
244 serial_set_attrs(&cur_attr);
245}
246
247void serial_scroll(ssize_t i)
248{
249 if (i > 0) {
250 serial_goto(0, scr_height - 1);
251 while (i--)
252 serial_puts("\033D");
253 } else if (i < 0) {
254 serial_goto(0, 0);
255 while (i++)
256 serial_puts("\033M");
257 }
258}
259
260/** Set scrolling region. */
261void serial_set_scroll_region(ipcarg_t last_row)
262{
263 char control[MAX_CONTROL];
264 snprintf(control, MAX_CONTROL, "\033[0;%ur", last_row);
265 serial_puts(control);
266}
267
268void serial_cursor_disable(void)
269{
270 serial_puts("\033[?25l");
271}
272
273void serial_cursor_enable(void)
274{
275 serial_puts("\033[?25h");
276}
277
278void serial_console_init(putc_function_t putc_fn, ipcarg_t w, ipcarg_t h)
279{
280 scr_width = w;
281 scr_height = h;
282 putc_function = putc_fn;
283}
284
285
286
287/** Draw text data to viewport.
288 *
289 * @param vport Viewport id
290 * @param data Text data.
291 * @param x Leftmost column of the area.
292 * @param y Topmost row of the area.
293 * @param w Number of rows.
294 * @param h Number of columns.
295 *
296 */
297static void draw_text_data(keyfield_t *data, ipcarg_t x, ipcarg_t y,
298 ipcarg_t w, ipcarg_t h)
299{
300 serial_goto(x, y);
301 ipcarg_t i;
302 ipcarg_t j;
303
304 attrs_t *a0 = &data[0].attrs;
305
306 for (j = 0; j < h; j++) {
307 if ((j > 0) && (w != scr_width))
308 serial_goto(x, j);
309
310 for (i = 0; i < w; i++) {
311 attrs_t *a1 = &data[j * w + i].attrs;
312
313 if (!attrs_same(*a0, *a1)) {
314 serial_set_attrs(a1);
315 a0 = a1;
316 }
317
318 serial_putchar(data[j * w + i].character);
319 }
320 }
321}
322
323/**
324 * Main function of the thread serving client connections.
325 */
326void serial_client_connection(ipc_callid_t iid, ipc_call_t *icall)
327{
328 keyfield_t *interbuf = NULL;
329 size_t intersize = 0;
330
331 if (client_connected) {
332 ipc_answer_0(iid, ELIMIT);
333 return;
334 }
335
336 client_connected = 1;
337 ipc_answer_0(iid, EOK);
338
339 /* Clear the terminal, set scrolling region
340 to 0 - height rows. */
341 serial_clrscr();
342 serial_goto(0, 0);
343 serial_set_scroll_region(scr_height);
344
345 while (true) {
346 ipc_call_t call;
347 ipc_callid_t callid = async_get_call(&call);
348
349 wchar_t c;
350 ipcarg_t col;
351 ipcarg_t row;
352 ipcarg_t w;
353 ipcarg_t h;
354 ssize_t rows;
355
356 int retval;
357
358 switch (IPC_GET_METHOD(call)) {
359 case IPC_M_PHONE_HUNGUP:
360 client_connected = 0;
361 ipc_answer_0(callid, EOK);
362
363 /* Exit thread */
364 return;
365 case IPC_M_SHARE_OUT:
366 /* We accept one area for data interchange */
367 intersize = IPC_GET_ARG2(call);
368 if (intersize >= scr_width * scr_height *
369 sizeof(*interbuf)) {
370 receive_comm_area(callid, &call,
371 (void *) &interbuf);
372 continue;
373 }
374
375 retval = EINVAL;
376 break;
377 case FB_DRAW_TEXT_DATA:
378 col = IPC_GET_ARG1(call);
379 row = IPC_GET_ARG2(call);
380 w = IPC_GET_ARG3(call);
381 h = IPC_GET_ARG4(call);
382
383 if (!interbuf) {
384 retval = EINVAL;
385 break;
386 }
387
388 if ((col + w > scr_width) || (row + h > scr_height)) {
389 retval = EINVAL;
390 break;
391 }
392
393 draw_text_data(interbuf, col, row, w, h);
394 lastcol = col + w;
395 lastrow = row + h - 1;
396 retval = 0;
397 break;
398 case FB_PUTCHAR:
399 c = IPC_GET_ARG1(call);
400 col = IPC_GET_ARG2(call);
401 row = IPC_GET_ARG3(call);
402
403 if ((lastcol != col) || (lastrow != row))
404 serial_goto(col, row);
405
406 lastcol = col + 1;
407 lastrow = row;
408 serial_putchar(c);
409 retval = 0;
410 break;
411 case FB_CURSOR_GOTO:
412 col = IPC_GET_ARG1(call);
413 row = IPC_GET_ARG2(call);
414 serial_goto(col, row);
415 lastcol = col;
416 lastrow = row;
417 retval = 0;
418 break;
419 case FB_GET_CSIZE:
420 ipc_answer_2(callid, EOK, scr_width, scr_height);
421 continue;
422 case FB_GET_COLOR_CAP:
423 ipc_answer_1(callid, EOK, color ? FB_CCAP_INDEXED :
424 FB_CCAP_STYLE);
425 continue;
426 case FB_CLEAR:
427 serial_clrscr();
428 retval = 0;
429 break;
430 case FB_SET_STYLE:
431 cur_attr.t = at_style;
432 cur_attr.a.s.style = IPC_GET_ARG1(call);
433 serial_set_attrs(&cur_attr);
434 retval = 0;
435 break;
436 case FB_SET_COLOR:
437 cur_attr.t = at_idx;
438 cur_attr.a.i.fg_color = IPC_GET_ARG1(call);
439 cur_attr.a.i.bg_color = IPC_GET_ARG2(call);
440 cur_attr.a.i.flags = IPC_GET_ARG3(call);
441 serial_set_attrs(&cur_attr);
442 retval = 0;
443 break;
444 case FB_SET_RGB_COLOR:
445 cur_attr.t = at_rgb;
446 cur_attr.a.r.fg_color = IPC_GET_ARG1(call);
447 cur_attr.a.r.bg_color = IPC_GET_ARG2(call);
448 serial_set_attrs(&cur_attr);
449 retval = 0;
450 break;
451 case FB_SCROLL:
452 rows = IPC_GET_ARG1(call);
453
454 if (rows >= 0) {
455 if ((ipcarg_t) rows > scr_height) {
456 retval = EINVAL;
457 break;
458 }
459 } else {
460 if ((ipcarg_t) (-rows) > scr_height) {
461 retval = EINVAL;
462 break;
463 }
464 }
465
466 serial_scroll(rows);
467 serial_goto(lastcol, lastrow);
468 retval = 0;
469 break;
470 case FB_CURSOR_VISIBILITY:
471 if(IPC_GET_ARG1(call))
472 serial_cursor_enable();
473 else
474 serial_cursor_disable();
475 retval = 0;
476 break;
477 case FB_SCREEN_YIELD:
478 serial_sgr(SGR_RESET);
479 serial_puts("\033[2J");
480 serial_goto(0, 0);
481 serial_cursor_enable();
482 retval = 0;
483 break;
484 case FB_SCREEN_RECLAIM:
485 serial_clrscr();
486 retval = 0;
487 break;
488 default:
489 retval = ENOENT;
490 }
491 ipc_answer_0(callid, retval);
492 }
493}
494
495/**
496 * @}
497 */
Note: See TracBrowser for help on using the repository browser.