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

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

Get rid of FB_WRITE. We can use FB_DRAW_TEXT_DATA if we extend it just a little bit.

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