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

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

do not provide general access to kernel headers from uspace, only allow specific headers to be accessed or shared
externalize headers which serve as kernel/uspace API/ABI into a special tree

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