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
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 <async.h>
42#include <ipc/fb.h>
43#include <bool.h>
44#include <errno.h>
45#include <io/color.h>
46#include <io/style.h>
47#include <str.h>
48#include <inttypes.h>
49#include <io/screenbuffer.h>
50
51#include "main.h"
52#include "serial_console.h"
53
54#define MAX_CONTROL 20
55
56static sysarg_t scr_width;
57static sysarg_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 sysarg_t lastcol = 0;
63static sysarg_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_UNDERLINE = 4,
87 SGR_BLINK = 5,
88 SGR_REVERSE = 7,
89 SGR_FGCOLOR = 30,
90 SGR_BGCOLOR = 40
91};
92
93static int color_map[] = {
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,
99 [COLOR_MAGENTA] = CI_MAGENTA,
100 [COLOR_YELLOW] = CI_BROWN,
101 [COLOR_WHITE] = CI_WHITE
102};
103
104void serial_puts(const char *str)
105{
106 while (*str)
107 putc_function(*(str++));
108}
109
110static void serial_putchar(wchar_t ch)
111{
112 if (utf8 != true) {
113 if (ch >= 0 && ch < 128)
114 (*putc_function)((uint8_t) ch);
115 else
116 (*putc_function)('?');
117
118 return;
119 }
120
121 size_t offs = 0;
122 char buf[STR_BOUNDS(1)];
123 if (chr_encode(ch, buf, &offs, STR_BOUNDS(1)) == EOK) {
124 size_t i;
125 for (i = 0; i < offs; i++)
126 (*putc_function)(buf[i]);
127 } else
128 (*putc_function)('?');
129}
130
131void serial_goto(const sysarg_t col, const sysarg_t row)
132{
133 if ((col > scr_width) || (row > scr_height))
134 return;
135
136 char control[MAX_CONTROL];
137 snprintf(control, MAX_CONTROL, "\033[%" PRIun ";%" PRIun "f",
138 row + 1, col + 1);
139 serial_puts(control);
140}
141
142/** ECMA-48 Set Graphics Rendition. */
143static void serial_sgr(const unsigned int mode)
144{
145 char control[MAX_CONTROL];
146 snprintf(control, MAX_CONTROL, "\033[%um", mode);
147 serial_puts(control);
148}
149
150static void serial_set_style(console_style_t style)
151{
152 switch (style) {
153 case STYLE_EMPHASIS:
154 serial_sgr(SGR_RESET);
155 if (color) {
156 serial_sgr(SGR_FGCOLOR + CI_RED);
157 serial_sgr(SGR_BGCOLOR + CI_WHITE);
158 }
159 serial_sgr(SGR_BOLD);
160 break;
161 case STYLE_INVERTED:
162 serial_sgr(SGR_RESET);
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:
170 serial_sgr(SGR_RESET);
171 if (color) {
172 serial_sgr(SGR_FGCOLOR + CI_WHITE);
173 serial_sgr(SGR_BGCOLOR + CI_RED);
174 } else
175 serial_sgr(SGR_UNDERLINE);
176 break;
177 default:
178 serial_sgr(SGR_RESET);
179 if (color) {
180 serial_sgr(SGR_FGCOLOR + CI_BLACK);
181 serial_sgr(SGR_BGCOLOR + CI_WHITE);
182 }
183 }
184}
185
186static void serial_set_idx(uint8_t fgcolor, uint8_t bgcolor,
187 uint8_t flags)
188{
189 serial_sgr(SGR_RESET);
190 if (color) {
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);
195 } else {
196 if (fgcolor >= bgcolor)
197 serial_sgr(SGR_REVERSE);
198 }
199}
200
201static void serial_set_rgb(uint32_t fgcolor, uint32_t bgcolor)
202{
203 serial_sgr(SGR_RESET);
204
205 if (fgcolor >= bgcolor)
206 serial_sgr(SGR_REVERSE);
207}
208
209static void serial_set_attrs(attrs_t *a)
210{
211 switch (a->t) {
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:
219 serial_set_idx(a->a.i.fg_color, a->a.i.bg_color,
220 a->a.i.flags);
221 break;
222 }
223}
224
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. */
253void serial_set_scroll_region(sysarg_t last_row)
254{
255 char control[MAX_CONTROL];
256 snprintf(control, MAX_CONTROL, "\033[0;%" PRIun "r", last_row);
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
270void serial_console_init(putc_function_t putc_fn, sysarg_t w, sysarg_t h)
271{
272 scr_width = w;
273 scr_height = h;
274 putc_function = putc_fn;
275}
276
277/** Draw text data to viewport.
278 *
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.
285 *
286 */
287static void draw_text_data(keyfield_t *data, sysarg_t x0, sysarg_t y0,
288 sysarg_t width, sysarg_t height)
289{
290 attrs_t *a0 = &data[0].attrs;
291 serial_set_attrs(a0);
292
293 sysarg_t y;
294 for (y = 0; y < height; y++) {
295 serial_goto(x0, y0 + y);
296
297 sysarg_t x;
298 for (x = 0; x < width; x++) {
299 attrs_t *attr = &data[y * width + x].attrs;
300
301 if (!attrs_same(*a0, *attr)) {
302 serial_set_attrs(attr);
303 a0 = attr;
304 }
305
306 serial_putchar(data[y * width + x].character);
307 }
308 }
309}
310
311/**
312 * Main function of the thread serving client connections.
313 */
314void serial_client_connection(ipc_callid_t iid, ipc_call_t *icall)
315{
316 keyfield_t *interbuf = NULL;
317 size_t intersize = 0;
318
319 if (client_connected) {
320 async_answer_0(iid, ELIMIT);
321 return;
322 }
323
324 client_connected = 1;
325 async_answer_0(iid, EOK);
326
327 /* Clear the terminal, set scrolling region
328 to 0 - height rows. */
329 serial_clrscr();
330 serial_goto(0, 0);
331 serial_set_scroll_region(scr_height);
332
333 while (true) {
334 ipc_call_t call;
335 ipc_callid_t callid = async_get_call(&call);
336
337 wchar_t c;
338 sysarg_t col;
339 sysarg_t row;
340 sysarg_t w;
341 sysarg_t h;
342 ssize_t rows;
343
344 int retval;
345
346 switch (IPC_GET_IMETHOD(call)) {
347 case IPC_M_PHONE_HUNGUP:
348 client_connected = 0;
349 async_answer_0(callid, EOK);
350
351 /* Exit thread */
352 return;
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 }
362
363 retval = EINVAL;
364 break;
365 case FB_DRAW_TEXT_DATA:
366 col = IPC_GET_ARG1(call);
367 row = IPC_GET_ARG2(call);
368 w = IPC_GET_ARG3(call);
369 h = IPC_GET_ARG4(call);
370
371 if (!interbuf) {
372 retval = EINVAL;
373 break;
374 }
375
376 if ((col + w > scr_width) || (row + h > scr_height)) {
377 retval = EINVAL;
378 break;
379 }
380
381 draw_text_data(interbuf, col, row, w, h);
382 lastcol = col + w;
383 lastrow = row + h - 1;
384 retval = 0;
385 break;
386 case FB_PUTCHAR:
387 c = IPC_GET_ARG1(call);
388 col = IPC_GET_ARG2(call);
389 row = IPC_GET_ARG3(call);
390
391 if ((lastcol != col) || (lastrow != row))
392 serial_goto(col, row);
393
394 lastcol = col + 1;
395 lastrow = row;
396 serial_putchar(c);
397 retval = 0;
398 break;
399 case FB_CURSOR_GOTO:
400 col = IPC_GET_ARG1(call);
401 row = IPC_GET_ARG2(call);
402 serial_goto(col, row);
403 lastcol = col;
404 lastrow = row;
405 retval = 0;
406 break;
407 case FB_GET_CSIZE:
408 async_answer_2(callid, EOK, scr_width, scr_height);
409 continue;
410 case FB_GET_COLOR_CAP:
411 async_answer_1(callid, EOK, color ? FB_CCAP_INDEXED :
412 FB_CCAP_STYLE);
413 continue;
414 case FB_CLEAR:
415 serial_clrscr();
416 retval = 0;
417 break;
418 case FB_SET_STYLE:
419 cur_attr.t = at_style;
420 cur_attr.a.s.style = IPC_GET_ARG1(call);
421 serial_set_attrs(&cur_attr);
422 retval = 0;
423 break;
424 case FB_SET_COLOR:
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);
429 serial_set_attrs(&cur_attr);
430 retval = 0;
431 break;
432 case FB_SET_RGB_COLOR:
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);
436 serial_set_attrs(&cur_attr);
437 retval = 0;
438 break;
439 case FB_SCROLL:
440 rows = IPC_GET_ARG1(call);
441
442 if (rows >= 0) {
443 if ((sysarg_t) rows > scr_height) {
444 retval = EINVAL;
445 break;
446 }
447 } else {
448 if ((sysarg_t) (-rows) > scr_height) {
449 retval = EINVAL;
450 break;
451 }
452 }
453
454 serial_scroll(rows);
455 serial_goto(lastcol, lastrow);
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;
465 case FB_SCREEN_YIELD:
466 serial_sgr(SGR_RESET);
467 serial_puts("\033[2J");
468 serial_goto(0, 0);
469 serial_cursor_enable();
470 retval = 0;
471 break;
472 case FB_SCREEN_RECLAIM:
473 serial_clrscr();
474 retval = 0;
475 break;
476 default:
477 retval = ENOENT;
478 }
479 async_answer_0(callid, retval);
480 }
481}
482
483/**
484 * @}
485 */
Note: See TracBrowser for help on using the repository browser.