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
RevLine 
[965dc18]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
[369a5f8]33 * @brief Serial console services (putc, puts, clear screen, cursor goto,...)
[965dc18]34 * @{
[369a5f8]35 */
[965dc18]36
37/** @file
38 */
39
40#include <stdio.h>
[8b97256]41#include <ipc/ipc.h>
42#include <async.h>
43#include <ipc/fb.h>
44#include <bool.h>
45#include <errno.h>
[8dc12ac]46#include <io/color.h>
47#include <io/style.h>
[19f857a]48#include <str.h>
[369a5f8]49#include <io/screenbuffer.h>
[965dc18]50
[16e9c476]51#include "main.h"
[965dc18]52#include "serial_console.h"
53
54#define MAX_CONTROL 20
55
[369a5f8]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. */
[965dc18]60static putc_function_t putc_function;
61
[369a5f8]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
[8b97256]69/* Allow only 1 connection */
70static int client_connected = 0;
71
[fb69f39]72enum sgr_color_index {
[369a5f8]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
[fb69f39]81};
82
83enum sgr_command {
[369a5f8]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,
[fb69f39]90 SGR_REVERSE_OFF = 27,
[369a5f8]91 SGR_FGCOLOR = 30,
92 SGR_BGCOLOR = 40
[fb69f39]93};
94
95static int color_map[] = {
[369a5f8]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,
[fb69f39]101 [COLOR_MAGENTA] = CI_MAGENTA,
[369a5f8]102 [COLOR_YELLOW] = CI_BROWN,
103 [COLOR_WHITE] = CI_WHITE
[fb69f39]104};
105
[a000878c]106void serial_puts(const char *str)
[965dc18]107{
108 while (*str)
109 putc_function(*(str++));
110}
111
[369a5f8]112static void serial_putchar(wchar_t ch)
[7ce3cb2]113{
[b27eb71]114 if (utf8 != true) {
115 if (ch >= 0 && ch < 128)
116 (*putc_function)((uint8_t) ch);
[369a5f8]117 else
[b27eb71]118 (*putc_function)('?');
[369a5f8]119
[b27eb71]120 return;
121 }
[369a5f8]122
123 size_t offs = 0;
124 char buf[STR_BOUNDS(1)];
[b27eb71]125 if (chr_encode(ch, buf, &offs, STR_BOUNDS(1)) == EOK) {
[369a5f8]126 size_t i;
[b27eb71]127 for (i = 0; i < offs; i++)
128 (*putc_function)(buf[i]);
[369a5f8]129 } else
[b27eb71]130 (*putc_function)('?');
[7ce3cb2]131}
132
[369a5f8]133void serial_goto(const ipcarg_t col, const ipcarg_t row)
[965dc18]134{
[8dc12ac]135 if ((col > scr_width) || (row > scr_height))
[965dc18]136 return;
137
[fb69f39]138 char control[MAX_CONTROL];
139 snprintf(control, MAX_CONTROL, "\033[%u;%uf", row + 1, col + 1);
[965dc18]140 serial_puts(control);
141}
142
[9805cde]143/** ECMA-48 Set Graphics Rendition. */
144static void serial_sgr(const unsigned int mode)
[965dc18]145{
146 char control[MAX_CONTROL];
147 snprintf(control, MAX_CONTROL, "\033[%um", mode);
148 serial_puts(control);
149}
150
[369a5f8]151static void serial_set_style(console_style_t style)
[965dc18]152{
[369a5f8]153 switch (style) {
154 case STYLE_EMPHASIS:
[16e9c476]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);
[369a5f8]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:
[16e9c476]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
[369a5f8]192static void serial_set_idx(uint8_t fgcolor, uint8_t bgcolor,
193 uint8_t flags)
[16e9c476]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{
[369a5f8]209 serial_sgr(SGR_RESET);
210
[16e9c476]211 if (fgcolor < bgcolor)
212 serial_sgr(SGR_REVERSE_OFF);
213 else
[8dc12ac]214 serial_sgr(SGR_REVERSE);
[16e9c476]215}
216
[369a5f8]217static void serial_set_attrs(attrs_t *a)
[16e9c476]218{
219 switch (a->t) {
[8dc12ac]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:
[369a5f8]227 serial_set_idx(a->a.i.fg_color, a->a.i.bg_color,
228 a->a.i.flags);
[8dc12ac]229 break;
[16e9c476]230 }
231}
232
[369a5f8]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
[dc033a1]287/** Draw text data to viewport.
288 *
289 * @param vport Viewport id
290 * @param data Text data.
[369a5f8]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 *
[dc033a1]296 */
[369a5f8]297static void draw_text_data(keyfield_t *data, ipcarg_t x, ipcarg_t y,
298 ipcarg_t w, ipcarg_t h)
[16e9c476]299{
[8dc12ac]300 serial_goto(x, y);
[369a5f8]301 ipcarg_t i;
302 ipcarg_t j;
303
304 attrs_t *a0 = &data[0].attrs;
305
[dc033a1]306 for (j = 0; j < h; j++) {
[369a5f8]307 if ((j > 0) && (w != scr_width))
[8dc12ac]308 serial_goto(x, j);
[369a5f8]309
[dc033a1]310 for (i = 0; i < w; i++) {
[369a5f8]311 attrs_t *a1 = &data[j * w + i].attrs;
312
313 if (!attrs_same(*a0, *a1)) {
[16e9c476]314 serial_set_attrs(a1);
[369a5f8]315 a0 = a1;
316 }
317
318 serial_putchar(data[j * w + i].character);
[16e9c476]319 }
320 }
321}
322
[8b97256]323/**
324 * Main function of the thread serving client connections.
325 */
326void serial_client_connection(ipc_callid_t iid, ipc_call_t *icall)
327{
[16e9c476]328 keyfield_t *interbuf = NULL;
329 size_t intersize = 0;
[8b97256]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);
[16e9c476]343 serial_set_scroll_region(scr_height);
[8b97256]344
345 while (true) {
[369a5f8]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
[8b97256]358 switch (IPC_GET_METHOD(call)) {
359 case IPC_M_PHONE_HUNGUP:
360 client_connected = 0;
361 ipc_answer_0(callid, EOK);
[369a5f8]362
363 /* Exit thread */
[8b97256]364 return;
[16e9c476]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 }
[369a5f8]374
[16e9c476]375 retval = EINVAL;
376 break;
377 case FB_DRAW_TEXT_DATA:
[dc033a1]378 col = IPC_GET_ARG1(call);
379 row = IPC_GET_ARG2(call);
380 w = IPC_GET_ARG3(call);
381 h = IPC_GET_ARG4(call);
[369a5f8]382
[16e9c476]383 if (!interbuf) {
384 retval = EINVAL;
385 break;
386 }
[369a5f8]387
[36e9cd1]388 if ((col + w > scr_width) || (row + h > scr_height)) {
[dc033a1]389 retval = EINVAL;
390 break;
391 }
[369a5f8]392
[dc033a1]393 draw_text_data(interbuf, col, row, w, h);
394 lastcol = col + w;
[8dc12ac]395 lastrow = row + h - 1;
[16e9c476]396 retval = 0;
397 break;
[8b97256]398 case FB_PUTCHAR:
399 c = IPC_GET_ARG1(call);
[8dc12ac]400 col = IPC_GET_ARG2(call);
401 row = IPC_GET_ARG3(call);
[369a5f8]402
[dc033a1]403 if ((lastcol != col) || (lastrow != row))
[8dc12ac]404 serial_goto(col, row);
[369a5f8]405
[dc033a1]406 lastcol = col + 1;
407 lastrow = row;
[7ce3cb2]408 serial_putchar(c);
[8b97256]409 retval = 0;
410 break;
411 case FB_CURSOR_GOTO:
[8dc12ac]412 col = IPC_GET_ARG1(call);
413 row = IPC_GET_ARG2(call);
414 serial_goto(col, row);
[dc033a1]415 lastcol = col;
[8dc12ac]416 lastrow = row;
[8b97256]417 retval = 0;
418 break;
419 case FB_GET_CSIZE:
[8dc12ac]420 ipc_answer_2(callid, EOK, scr_width, scr_height);
[8b97256]421 continue;
[50cfa6c]422 case FB_GET_COLOR_CAP:
423 ipc_answer_1(callid, EOK, color ? FB_CCAP_INDEXED :
424 FB_CCAP_STYLE);
425 continue;
[8b97256]426 case FB_CLEAR:
427 serial_clrscr();
428 retval = 0;
429 break;
430 case FB_SET_STYLE:
[53e197f]431 cur_attr.t = at_style;
432 cur_attr.a.s.style = IPC_GET_ARG1(call);
[10270a8]433 serial_set_attrs(&cur_attr);
[9805cde]434 retval = 0;
435 break;
436 case FB_SET_COLOR:
[53e197f]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);
[10270a8]441 serial_set_attrs(&cur_attr);
[9805cde]442 retval = 0;
443 break;
444 case FB_SET_RGB_COLOR:
[53e197f]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);
[10270a8]448 serial_set_attrs(&cur_attr);
[8b97256]449 retval = 0;
450 break;
451 case FB_SCROLL:
[369a5f8]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 }
[8b97256]464 }
[369a5f8]465
466 serial_scroll(rows);
[8dc12ac]467 serial_goto(lastcol, lastrow);
[8b97256]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;
[ebfabf6]477 case FB_SCREEN_YIELD:
[10270a8]478 serial_sgr(SGR_RESET);
479 serial_puts("\033[2J");
480 serial_goto(0, 0);
481 serial_cursor_enable();
482 retval = 0;
483 break;
[ebfabf6]484 case FB_SCREEN_RECLAIM:
485 serial_clrscr();
486 retval = 0;
487 break;
[8b97256]488 default:
489 retval = ENOENT;
490 }
491 ipc_answer_0(callid, retval);
492 }
493}
494
[8dc12ac]495/**
[965dc18]496 * @}
497 */
Note: See TracBrowser for help on using the repository browser.