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

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

add STYLE_SELECTED and STYLE_INVERTED into serial output driver
move screenbuffer.{c|h} into libc, make it slightly more generic
collateral changes

  • 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 attrs_t attr;
355 ssize_t rows;
356
357 int retval;
358
359 switch (IPC_GET_METHOD(call)) {
360 case IPC_M_PHONE_HUNGUP:
361 client_connected = 0;
362 ipc_answer_0(callid, EOK);
363
364 /* Exit thread */
365 return;
366 case IPC_M_SHARE_OUT:
367 /* We accept one area for data interchange */
368 intersize = IPC_GET_ARG2(call);
369 if (intersize >= scr_width * scr_height *
370 sizeof(*interbuf)) {
371 receive_comm_area(callid, &call,
372 (void *) &interbuf);
373 continue;
374 }
375
376 retval = EINVAL;
377 break;
378 case FB_DRAW_TEXT_DATA:
379 col = IPC_GET_ARG1(call);
380 row = IPC_GET_ARG2(call);
381 w = IPC_GET_ARG3(call);
382 h = IPC_GET_ARG4(call);
383
384 if (!interbuf) {
385 retval = EINVAL;
386 break;
387 }
388
389 if ((col + w > scr_width) || (row + h > scr_height)) {
390 retval = EINVAL;
391 break;
392 }
393
394 draw_text_data(interbuf, col, row, w, h);
395 lastcol = col + w;
396 lastrow = row + h - 1;
397 retval = 0;
398 break;
399 case FB_PUTCHAR:
400 c = IPC_GET_ARG1(call);
401 col = IPC_GET_ARG2(call);
402 row = IPC_GET_ARG3(call);
403
404 if ((lastcol != col) || (lastrow != row))
405 serial_goto(col, row);
406
407 lastcol = col + 1;
408 lastrow = row;
409 serial_putchar(c);
410 retval = 0;
411 break;
412 case FB_CURSOR_GOTO:
413 col = IPC_GET_ARG1(call);
414 row = IPC_GET_ARG2(call);
415 serial_goto(col, row);
416 lastcol = col;
417 lastrow = row;
418 retval = 0;
419 break;
420 case FB_GET_CSIZE:
421 ipc_answer_2(callid, EOK, scr_width, scr_height);
422 continue;
423 case FB_GET_COLOR_CAP:
424 ipc_answer_1(callid, EOK, color ? FB_CCAP_INDEXED :
425 FB_CCAP_STYLE);
426 continue;
427 case FB_CLEAR:
428 serial_clrscr();
429 retval = 0;
430 break;
431 case FB_SET_STYLE:
432 attr.t = at_style;
433 attr.a.s.style = IPC_GET_ARG1(call);
434 serial_set_attrs(&cur_attr);
435 retval = 0;
436 break;
437 case FB_SET_COLOR:
438 attr.t = at_idx;
439 attr.a.i.fg_color = IPC_GET_ARG1(call);
440 attr.a.i.bg_color = IPC_GET_ARG2(call);
441 attr.a.i.flags = IPC_GET_ARG3(call);
442 serial_set_attrs(&cur_attr);
443 retval = 0;
444 break;
445 case FB_SET_RGB_COLOR:
446 attr.t = at_rgb;
447 attr.a.r.fg_color = IPC_GET_ARG1(call);
448 attr.a.r.bg_color = IPC_GET_ARG2(call);
449 serial_set_attrs(&cur_attr);
450 retval = 0;
451 break;
452 case FB_SCROLL:
453 rows = IPC_GET_ARG1(call);
454
455 if (rows >= 0) {
456 if ((ipcarg_t) rows > scr_height) {
457 retval = EINVAL;
458 break;
459 }
460 } else {
461 if ((ipcarg_t) (-rows) > scr_height) {
462 retval = EINVAL;
463 break;
464 }
465 }
466
467 serial_scroll(rows);
468 serial_goto(lastcol, lastrow);
469 retval = 0;
470 break;
471 case FB_CURSOR_VISIBILITY:
472 if(IPC_GET_ARG1(call))
473 serial_cursor_enable();
474 else
475 serial_cursor_disable();
476 retval = 0;
477 break;
478 case FB_SCREEN_YIELD:
479 serial_sgr(SGR_RESET);
480 serial_puts("\033[2J");
481 serial_goto(0, 0);
482 serial_cursor_enable();
483 retval = 0;
484 break;
485 case FB_SCREEN_RECLAIM:
486 serial_clrscr();
487 retval = 0;
488 break;
489 default:
490 retval = ENOENT;
491 }
492 ipc_answer_0(callid, retval);
493 }
494}
495
496/**
497 * @}
498 */
Note: See TracBrowser for help on using the repository browser.