source: mainline/uspace/srv/fb/serial_console.c@ ccd1a14

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ccd1a14 was ebfabf6, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

Use better method names.

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