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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1a5b252 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
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// FIXME: remove this header
55#include <abi/ipc/methods.h>
56
57#define MAX_CONTROL 20
58
59static sysarg_t scr_width;
60static sysarg_t scr_height;
61static bool color = true; /**< True if producing color output. */
62static bool utf8 = false; /**< True if producing UTF8 output. */
63static putc_function_t putc_function;
64
65static sysarg_t lastcol = 0;
66static sysarg_t lastrow = 0;
67static attrs_t cur_attr = {
68 .t = at_style,
69 .a.s.style = STYLE_NORMAL
70};
71
72/* Allow only 1 connection */
73static int client_connected = 0;
74
75enum sgr_color_index {
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
84};
85
86enum sgr_command {
87 SGR_RESET = 0,
88 SGR_BOLD = 1,
89 SGR_UNDERLINE = 4,
90 SGR_BLINK = 5,
91 SGR_REVERSE = 7,
92 SGR_FGCOLOR = 30,
93 SGR_BGCOLOR = 40
94};
95
96static int color_map[] = {
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,
102 [COLOR_MAGENTA] = CI_MAGENTA,
103 [COLOR_YELLOW] = CI_BROWN,
104 [COLOR_WHITE] = CI_WHITE
105};
106
107void serial_puts(const char *str)
108{
109 while (*str)
110 putc_function(*(str++));
111}
112
113static void serial_putchar(wchar_t ch)
114{
115 if (utf8 != true) {
116 if (ch >= 0 && ch < 128)
117 (*putc_function)((uint8_t) ch);
118 else
119 (*putc_function)('?');
120
121 return;
122 }
123
124 size_t offs = 0;
125 char buf[STR_BOUNDS(1)];
126 if (chr_encode(ch, buf, &offs, STR_BOUNDS(1)) == EOK) {
127 size_t i;
128 for (i = 0; i < offs; i++)
129 (*putc_function)(buf[i]);
130 } else
131 (*putc_function)('?');
132}
133
134void serial_goto(const sysarg_t col, const sysarg_t row)
135{
136 if ((col > scr_width) || (row > scr_height))
137 return;
138
139 char control[MAX_CONTROL];
140 snprintf(control, MAX_CONTROL, "\033[%" PRIun ";%" PRIun "f",
141 row + 1, col + 1);
142 serial_puts(control);
143}
144
145/** ECMA-48 Set Graphics Rendition. */
146static void serial_sgr(const unsigned int mode)
147{
148 char control[MAX_CONTROL];
149 snprintf(control, MAX_CONTROL, "\033[%um", mode);
150 serial_puts(control);
151}
152
153static void serial_set_style(console_style_t style)
154{
155 switch (style) {
156 case STYLE_EMPHASIS:
157 serial_sgr(SGR_RESET);
158 if (color) {
159 serial_sgr(SGR_FGCOLOR + CI_RED);
160 serial_sgr(SGR_BGCOLOR + CI_WHITE);
161 }
162 serial_sgr(SGR_BOLD);
163 break;
164 case STYLE_INVERTED:
165 serial_sgr(SGR_RESET);
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:
173 serial_sgr(SGR_RESET);
174 if (color) {
175 serial_sgr(SGR_FGCOLOR + CI_WHITE);
176 serial_sgr(SGR_BGCOLOR + CI_RED);
177 } else
178 serial_sgr(SGR_UNDERLINE);
179 break;
180 default:
181 serial_sgr(SGR_RESET);
182 if (color) {
183 serial_sgr(SGR_FGCOLOR + CI_BLACK);
184 serial_sgr(SGR_BGCOLOR + CI_WHITE);
185 }
186 }
187}
188
189static void serial_set_idx(uint8_t fgcolor, uint8_t bgcolor,
190 uint8_t flags)
191{
192 serial_sgr(SGR_RESET);
193 if (color) {
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);
198 } else {
199 if (fgcolor >= bgcolor)
200 serial_sgr(SGR_REVERSE);
201 }
202}
203
204static void serial_set_rgb(uint32_t fgcolor, uint32_t bgcolor)
205{
206 serial_sgr(SGR_RESET);
207
208 if (fgcolor >= bgcolor)
209 serial_sgr(SGR_REVERSE);
210}
211
212static void serial_set_attrs(attrs_t *a)
213{
214 switch (a->t) {
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:
222 serial_set_idx(a->a.i.fg_color, a->a.i.bg_color,
223 a->a.i.flags);
224 break;
225 }
226}
227
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. */
256void serial_set_scroll_region(sysarg_t last_row)
257{
258 char control[MAX_CONTROL];
259 snprintf(control, MAX_CONTROL, "\033[0;%" PRIun "r", last_row);
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
273void serial_console_init(putc_function_t putc_fn, sysarg_t w, sysarg_t h)
274{
275 scr_width = w;
276 scr_height = h;
277 putc_function = putc_fn;
278}
279
280/** Draw text data to viewport.
281 *
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.
288 *
289 */
290static void draw_text_data(keyfield_t *data, sysarg_t x0, sysarg_t y0,
291 sysarg_t width, sysarg_t height)
292{
293 attrs_t *a0 = &data[0].attrs;
294 serial_set_attrs(a0);
295
296 sysarg_t y;
297 for (y = 0; y < height; y++) {
298 serial_goto(x0, y0 + y);
299
300 sysarg_t x;
301 for (x = 0; x < width; x++) {
302 attrs_t *attr = &data[y * width + x].attrs;
303
304 if (!attrs_same(*a0, *attr)) {
305 serial_set_attrs(attr);
306 a0 = attr;
307 }
308
309 serial_putchar(data[y * width + x].character);
310 }
311 }
312}
313
314/**
315 * Main function of the thread serving client connections.
316 */
317void serial_client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
318{
319 keyfield_t *interbuf = NULL;
320 size_t intersize = 0;
321
322 if (client_connected) {
323 async_answer_0(iid, ELIMIT);
324 return;
325 }
326
327 client_connected = 1;
328 async_answer_0(iid, EOK);
329
330 /* Clear the terminal, set scrolling region
331 to 0 - height rows. */
332 serial_clrscr();
333 serial_goto(0, 0);
334 serial_set_scroll_region(scr_height);
335
336 while (true) {
337 ipc_call_t call;
338 ipc_callid_t callid = async_get_call(&call);
339
340 wchar_t c;
341 sysarg_t col;
342 sysarg_t row;
343 sysarg_t w;
344 sysarg_t h;
345 ssize_t rows;
346
347 int retval;
348
349 if (!IPC_GET_IMETHOD(call)) {
350 client_connected = 0;
351 async_answer_0(callid, EOK);
352
353 /* Exit thread */
354 return;
355 }
356
357 switch (IPC_GET_IMETHOD(call)) {
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 }
367
368 retval = EINVAL;
369 break;
370 case FB_DRAW_TEXT_DATA:
371 col = IPC_GET_ARG1(call);
372 row = IPC_GET_ARG2(call);
373 w = IPC_GET_ARG3(call);
374 h = IPC_GET_ARG4(call);
375
376 if (!interbuf) {
377 retval = EINVAL;
378 break;
379 }
380
381 if ((col + w > scr_width) || (row + h > scr_height)) {
382 retval = EINVAL;
383 break;
384 }
385
386 draw_text_data(interbuf, col, row, w, h);
387 lastcol = col + w;
388 lastrow = row + h - 1;
389 retval = 0;
390 break;
391 case FB_PUTCHAR:
392 c = IPC_GET_ARG1(call);
393 col = IPC_GET_ARG2(call);
394 row = IPC_GET_ARG3(call);
395
396 if ((lastcol != col) || (lastrow != row))
397 serial_goto(col, row);
398
399 lastcol = col + 1;
400 lastrow = row;
401 serial_putchar(c);
402 retval = 0;
403 break;
404 case FB_CURSOR_GOTO:
405 col = IPC_GET_ARG1(call);
406 row = IPC_GET_ARG2(call);
407 serial_goto(col, row);
408 lastcol = col;
409 lastrow = row;
410 retval = 0;
411 break;
412 case FB_GET_CSIZE:
413 async_answer_2(callid, EOK, scr_width, scr_height);
414 continue;
415 case FB_GET_COLOR_CAP:
416 async_answer_1(callid, EOK, color ? FB_CCAP_INDEXED :
417 FB_CCAP_STYLE);
418 continue;
419 case FB_CLEAR:
420 serial_clrscr();
421 retval = 0;
422 break;
423 case FB_SET_STYLE:
424 cur_attr.t = at_style;
425 cur_attr.a.s.style = IPC_GET_ARG1(call);
426 serial_set_attrs(&cur_attr);
427 retval = 0;
428 break;
429 case FB_SET_COLOR:
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);
434 serial_set_attrs(&cur_attr);
435 retval = 0;
436 break;
437 case FB_SET_RGB_COLOR:
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);
441 serial_set_attrs(&cur_attr);
442 retval = 0;
443 break;
444 case FB_SCROLL:
445 rows = IPC_GET_ARG1(call);
446
447 if (rows >= 0) {
448 if ((sysarg_t) rows > scr_height) {
449 retval = EINVAL;
450 break;
451 }
452 } else {
453 if ((sysarg_t) (-rows) > scr_height) {
454 retval = EINVAL;
455 break;
456 }
457 }
458
459 serial_scroll(rows);
460 serial_goto(lastcol, lastrow);
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;
470 case FB_SCREEN_YIELD:
471 serial_sgr(SGR_RESET);
472 serial_puts("\033[2J");
473 serial_goto(0, 0);
474 serial_cursor_enable();
475 retval = 0;
476 break;
477 case FB_SCREEN_RECLAIM:
478 serial_clrscr();
479 retval = 0;
480 break;
481 default:
482 retval = ENOENT;
483 }
484 async_answer_0(callid, retval);
485 }
486}
487
488/**
489 * @}
490 */
Note: See TracBrowser for help on using the repository browser.