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

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