3 * \brief A terminal using an L4Re::Framebuffer via L4::Con
6 * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
11 * economic rights: Technische Universität Dresden (Germany)
13 * This file is part of TUD:OS and distributed under the terms of the
14 * GNU General Public License 2.
15 * Please see the COPYING-GPL-2 file for details.
18 #include <l4/re/console>
20 #include <l4/re/event>
21 #include <l4/re/event_enums.h>
22 #include <l4/re/namespace>
23 #include <l4/re/util/cap_alloc>
24 #include <l4/re/util/video/goos_fb>
25 #include <l4/re/util/object_registry>
26 #include <l4/sys/err.h>
27 #include <l4/sys/kdebug.h>
28 #include <l4/libgfxbitmap/font.h>
29 #include <l4/libgfxbitmap/support>
30 #include <l4/lib_vt100/vt100.h>
31 #include <l4/event/event>
32 #include <l4/cxx/ipc_stream>
33 #include <l4/cxx/ipc_server>
34 #include <l4/cxx/exceptions>
35 #include <l4/re/protocols>
36 #include <l4/re/log-sys.h>
37 #include <l4/util/util.h>
38 #include <l4/re/util/icu_svr>
39 #include <l4/re/util/vcon_svr>
40 #include <l4/sys/typeinfo_svr>
42 #include <pthread-l4.h>
50 static L4Re::Util::Video::Goos_fb fb;
52 static L4::Cap<L4Re::Dataspace> ev_ds;
53 static L4::Cap<L4::Irq> ev_irq;
55 static L4Re::Event_buffer ev_buffer;
57 static L4Re::Video::View::Info fbi;
58 static l4_uint32_t fn_x, fn_y;
60 // vt100 interpreter of ouput stream from client
63 static L4::Cap<void> rcv_cap()
65 static L4::Cap<void> r = L4Re::Util::cap_alloc.alloc<void>();
70 class Terminal : public L4::Server_object,
71 public L4Re::Util::Icu_cap_array_svr<Terminal>,
72 public L4Re::Util::Vcon_svr<Terminal>
75 typedef L4Re::Util::Icu_cap_array_svr<Terminal> Icu_svr;
76 typedef L4Re::Util::Vcon_svr<Terminal> Vcon_svr;
79 int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
81 void trigger() { _irq.trigger(); }
83 static L4::Cap<void> rcv_cap() { return ::rcv_cap(); }
85 unsigned vcon_read(char *buf, unsigned size) throw();
86 void vcon_write(const char *buf, unsigned size) throw();
87 int vcon_set_attr(l4_vcon_attr_t const *attr) throw();
88 int vcon_get_attr(l4_vcon_attr_t *attr) throw();
97 // vt100 interpreter backend
98 static void con_puts(termstate_t *term, int x, int y, l4_int8_t *s, int len,
99 unsigned fg, unsigned bg)
102 gfxbitmap_font_text(fb_addr, (l4re_video_view_info_t *)&fbi,
103 0, (char*)s, len, fn_x * x, fn_y * y, fg, bg);
105 fb.refresh(fn_x * x, fn_y * y, fn_x * len, fn_y);
108 termstate_t *term_init(int cols, int rows, int hist)
111 termstate_t *term = (termstate_t *)malloc(sizeof(termstate_t));
114 printf("malloc for new term failed");
118 // explizitely init. these, as they may be freed in init_termstate
124 if ((vt100_init(term, cols, rows, hist)))
133 static const char* init()
135 // initialize cons frontend
139 fb_addr = fb.attach_buffer();
141 if (fb.view_info(&fbi))
142 return "Cannot get framebuffer info\n";
144 gfxbitmap_font_init();
145 fn_x = gfxbitmap_font_width(0);
146 fn_y = gfxbitmap_font_height(0);
148 // convert colors to the format used by our framebuffer
149 libterm_init_colors(&fbi);
151 // initialize terminal library
152 term = term_init(fbi.width / fn_x, fbi.height / fn_y, 50);
154 // initialize input event handling
156 ev_ds = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
157 if (!ev_ds.is_valid())
158 return "Cannot allocate cap\n";
160 ev_irq = L4Re::Util::cap_alloc.alloc<L4::Irq>();
161 if (!ev_irq.is_valid())
162 return "Cannot allocate cap\n";
164 if (l4_error(L4Re::Env::env()->factory()->create_irq(ev_irq)))
165 return "Could not create event IRQ\n";
167 if (l4_error(L4::cap_cast<L4Re::Console>(fb.goos())->bind(0, ev_irq)))
168 return "Could not bind event IRQ\n";
170 if (L4::cap_cast<L4Re::Console>(fb.goos())->get_buffer(ev_ds))
171 return "Cannot get event dataspace and irq\n";
173 l4_addr_t sz = ev_ds->size();
176 if (L4Re::Env::env()->rm()->attach(&_buf, sz, L4Re::Rm::Search_addr, ev_ds))
177 return "Cannot attach event dataspace\n";
179 ev_buffer = L4Re::Event_buffer(_buf, sz);
185 touch_repeat(termstate_t * term, unsigned code, unsigned repeat)
187 (void)term; (void)code; (void)repeat;
190 void event_handler(void *data)
193 L4Re::Event_buffer::Event *e;
196 while ((e = ev_buffer.next()))
198 switch (e->payload.type)
203 switch (e->payload.code)
205 case L4RE_KEY_RIGHTSHIFT: // modifiers
206 case L4RE_KEY_LEFTSHIFT:
207 if (e->payload.value)
211 touch_repeat(term, e->payload.code, 0);
213 case L4RE_KEY_LEFTCTRL:
214 case L4RE_KEY_RIGHTCTRL:
215 if (e->payload.value)
219 touch_repeat(term, e->payload.code, 0);
221 case L4RE_KEY_LEFTALT:
222 if (e->payload.value)
226 touch_repeat(term, e->payload.code, 0);
228 case L4RE_KEY_RIGHTALT:
229 if (e->payload.value)
233 touch_repeat(term, e->payload.code, 0);
235 case L4RE_KEY_PAGEUP: // special terminal movement chars
236 if (e->payload.value && term->__shift)
238 vt100_scroll_up(term, term->phys_h / 2); // scroll for half screen
240 touch_repeat(term, e->payload.code, e->payload.value);
243 case L4RE_KEY_PAGEDOWN:
244 if (e->payload.value && term->__shift)
246 vt100_scroll_down(term, term->phys_h / 2); // scroll for half screen
248 touch_repeat(term, e->payload.code, e->payload.value);
252 if (e->payload.value) // regular chars
253 vt100_add_key(term, e->payload.code);
254 touch_repeat(term, e->payload.code, e->payload.value);
263 LOG("vt100_redraw()");
270 //LOGl("Event = %d", e->payload.type);
281 // convert attributes to corresponding gfxbitmap_color_pix_t
282 static void attribs_to_colors(l4_int8_t a, gfxbitmap_color_pix_t *fg,
283 gfxbitmap_color_pix_t *bg)
287 unpack_attribs(a, &fg_i, &bg_i, &in);
288 *fg = libterm_get_color(in, fg_i);
289 *bg = libterm_get_color(in, bg_i);
292 // redraw whole screen
293 void vt100_redraw(termstate_t *term)
296 int old_x = 0, old_y = 0;
298 l4_int8_t old_attrib = 0;
300 gfxbitmap_color_pix_t fg, bg;
302 // LOGl("term = %p, text = %p, color = %p", term, term->text, term->color);
305 // correct y for vis offset
306 for (y = 0 - term->vis_off; y < term->phys_h - term->vis_off; y++)
308 for (x = 0; x < term->w; x++)
310 //vt100_redraw_xy(term, x, y);
312 // if we observe a change in attributes, send the
313 // accumulated string
314 if (s != NULL && old_attrib != term->attrib[xy2index(term, x, y)])
316 attribs_to_colors(old_attrib, &fg, &bg);
317 // correct y for vis offset
318 con_puts(term, old_x, old_y + term->vis_off, s,
319 xy2index(term, x, y) - old_index, fg, bg);
322 // start a new string
325 old_index = xy2index(term, x, y);
326 s = term->text + old_index;
327 old_attrib = term->attrib[old_index];
332 // care for end of line remainder strings
335 attribs_to_colors(old_attrib, &fg, &bg);
336 // correct y for vis offset
337 con_puts(term, old_x, old_y + term->vis_off, s,
338 xy2index(term, x - 1, y) - old_index + 1, fg, bg);
344 void vt100_redraw_xy(termstate_t *term, int x, int y)
346 gfxbitmap_color_pix_t fg, bg;
350 // if out of bound, do nothing
351 if (y + term->vis_off >= term->phys_h)
356 c = term->text + xy2index(term, x, y);
357 a = term->attrib[xy2index(term, x, y)];
358 attribs_to_colors(a, &fg, &bg);
359 // correct for moved vis
360 con_puts(term, x, y + term->vis_off, c, 1, fg, bg);
363 // vt100 backends, currently not implemented
364 void vt100_hide_cursor(termstate_t *term)
366 if (term->cursor_vis)
368 // if the cursor is in visible area...
369 if ( (term->cur_y + term->vis_off) <= term->phys_h )
371 int bg, fg, intensity;
372 int index = xy2index( term, term->cur_x, term->cur_y );
374 unpack_attribs( term->attrib[index], &fg, &bg, &intensity );
375 term->attrib[index] = pack_attribs( bg, fg, intensity );
377 // only redraw if cursor is visible
378 vt100_redraw_xy( term, term->cur_x, term->cur_y );
383 void vt100_show_cursor(termstate_t *term)
385 if (term->cursor_vis)
387 if ( (term->cur_y + term->vis_off) <= term->phys_h )
389 int bg, fg, intensity;
390 int index = xy2index( term, term->cur_x, term->cur_y );
392 unpack_attribs( term->attrib[index], &fg, &bg, &intensity );
393 term->attrib[index] = pack_attribs( bg, fg, intensity );
395 // only redraw if cursor is visible
396 vt100_redraw_xy( term, term->cur_x, term->cur_y );
402 static L4Re::Util::Object_registry term_registry;
410 Terminal::vcon_write(const char *buf, unsigned len) throw()
413 memcpy(mbuf, buf, len);
415 //printf("%d: %.*s\n", len, (int)len, mbuf);
418 vt100_write(term, mbuf, len);
420 L4Re::Env::env()->log()->printn(mbuf, len);
424 Terminal::vcon_read(char *buf, unsigned len) throw()
428 while (len && (c = vt100_trygetchar(term)) != -1)
438 Terminal::vcon_set_attr(l4_vcon_attr_t const *attr) throw()
440 term->echo = attr->l_flags & L4_VCON_ECHO;
441 term->newline = attr->o_flags & L4_VCON_ONLCR;
446 Terminal::vcon_get_attr(l4_vcon_attr_t *attr) throw()
448 attr->l_flags = term->echo ? L4_VCON_ECHO : 0;
449 attr->o_flags = term->newline ? L4_VCON_ONLCR : 0;
455 Terminal::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
462 case L4::Meta::Protocol:
463 return L4::Util::handle_meta_request<L4::Vcon>(ios);
464 case L4::Irq::Protocol:
465 return Icu_svr::dispatch(obj, ios);
466 case L4::Vcon::Protocol:
467 return Vcon_svr::dispatch(obj, ios);
469 return -L4_EBADPROTO;
473 class Controller : public L4::Server_object
476 int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
480 Controller::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
487 case L4::Meta::Protocol:
488 return L4::Util::handle_meta_request<L4::Factory>(ios);
489 case L4::Factory::Protocol:
492 return -L4_EBADPROTO;
495 L4::Factory::Proto op;
500 case L4::Vcon::Protocol:
504 Terminal *t = new Terminal;
505 ios << term_registry.register_obj(t);
507 catch (L4::Runtime_error const &e)
511 catch (std::bad_alloc const &)
523 : public L4::Ipc_svr::Default_timeout,
524 public L4::Ipc_svr::Ignore_errors,
525 public L4::Ipc_svr::Compound_reply
527 void setup_wait(L4::Ipc_istream &istr, L4::Ipc_svr::Reply_mode)
530 istr << L4::Small_buf(rcv_cap().cap(), L4_RCV_ITEM_LOCAL_ID);
531 l4_utcb_br_u(istr.utcb())->bdr = 0;
535 static L4::Server<My_hooks> server(l4_utcb());
539 const char* error = init();
546 Event::Event event(ev_irq, event_handler, 0, 0xff);
547 if (!event.attached())
551 term_registry.register_obj(&_terminal, "term");
552 terminal = &_terminal;
553 if (!term_registry.register_obj(&_terminal, "term"))
555 printf("Terminal registration failed.\n");
562 if (!term_registry.register_obj(&ctrl, "terminal"))
564 printf("Terminal ctrl registration failed.\n");
569 server.loop(term_registry);