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

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

do not intermix low-level IPC methods with async framework methods

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