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/sys/typeinfo_svr>
41 #include <pthread-l4.h>
49 static L4Re::Util::Video::Goos_fb fb;
51 static L4::Cap<L4Re::Dataspace> ev_ds;
52 static L4::Cap<L4::Irq> ev_irq;
54 static L4Re::Event_buffer ev_buffer;
56 static L4Re::Video::View::Info fbi;
57 static l4_uint32_t fn_x, fn_y;
59 // vt100 interpreter of ouput stream from client
62 static L4::Cap<void> rcv_cap()
64 static L4::Cap<void> r = L4Re::Util::cap_alloc.alloc<void>();
69 class Terminal : public L4::Server_object,
70 public L4Re::Util::Icu_cap_array_svr<Terminal>
73 typedef L4Re::Util::Icu_cap_array_svr<Terminal> Icu_svr;
76 int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
78 void trigger() { _irq.trigger(); }
80 static L4::Cap<void> rcv_cap() { return ::rcv_cap(); }
89 // vt100 interpreter backend
90 static void con_puts(termstate_t *term, int x, int y, l4_int8_t *s, int len,
91 unsigned fg, unsigned bg)
94 gfxbitmap_font_text(fb_addr, (l4re_video_view_info_t *)&fbi,
95 0, (char*)s, len, fn_x * x, fn_y * y, fg, bg);
97 fb.refresh(fn_x * x, fn_y * y, fn_x * len, fn_y);
100 termstate_t *term_init(int cols, int rows, int hist)
103 termstate_t *term = (termstate_t *)malloc(sizeof(termstate_t));
106 printf("malloc for new term failed");
110 // explizitely init. these, as they may be freed in init_termstate
115 if ((vt100_init(term, cols, rows, hist)))
124 static const char* init()
126 // initialize cons frontend
130 fb_addr = fb.attach_buffer();
132 if (fb.view_info(&fbi))
133 return "Cannot get framebuffer info\n";
135 gfxbitmap_font_init();
136 fn_x = gfxbitmap_font_width(0);
137 fn_y = gfxbitmap_font_height(0);
139 // convert colors to the format used by our framebuffer
140 libterm_init_colors(&fbi);
142 // initialize terminal library
143 term = term_init(fbi.width / fn_x, fbi.height / fn_y, 50);
145 // initialize input event handling
147 ev_ds = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
148 if (!ev_ds.is_valid())
149 return "Cannot allocate cap\n";
151 ev_irq = L4Re::Util::cap_alloc.alloc<L4::Irq>();
152 if (!ev_irq.is_valid())
153 return "Cannot allocate cap\n";
155 if (l4_error(L4Re::Env::env()->factory()->create_irq(ev_irq)))
156 return "Could not create event IRQ\n";
158 if (l4_error(L4::cap_cast<L4Re::Console>(fb.goos())->bind(0, ev_irq)))
159 return "Could not bind event IRQ\n";
161 if (L4::cap_cast<L4Re::Console>(fb.goos())->get_buffer(ev_ds))
162 return "Cannot get event dataspace and irq\n";
164 l4_addr_t sz = ev_ds->size();
167 if (L4Re::Env::env()->rm()->attach(&_buf, sz, L4Re::Rm::Search_addr, ev_ds))
168 return "Cannot attach event dataspace\n";
170 ev_buffer = L4Re::Event_buffer(_buf, sz);
176 touch_repeat(termstate_t * term, unsigned code, unsigned repeat)
178 (void)term; (void)code; (void)repeat;
181 void event_handler(void *data)
184 L4Re::Event_buffer::Event *e;
187 while ((e = ev_buffer.next()))
189 switch (e->payload.type)
194 switch (e->payload.code)
196 case L4RE_KEY_RIGHTSHIFT: // modifiers
197 case L4RE_KEY_LEFTSHIFT:
198 if (e->payload.value)
202 touch_repeat(term, e->payload.code, 0);
204 case L4RE_KEY_LEFTCTRL:
205 case L4RE_KEY_RIGHTCTRL:
206 if (e->payload.value)
210 touch_repeat(term, e->payload.code, 0);
212 case L4RE_KEY_LEFTALT:
213 if (e->payload.value)
217 touch_repeat(term, e->payload.code, 0);
219 case L4RE_KEY_RIGHTALT:
220 if (e->payload.value)
224 touch_repeat(term, e->payload.code, 0);
226 case L4RE_KEY_PAGEUP: // special terminal movement chars
227 if (e->payload.value && term->__shift)
229 vt100_scroll_up(term, term->phys_h / 2); // scroll for half screen
231 touch_repeat(term, e->payload.code, e->payload.value);
234 case L4RE_KEY_PAGEDOWN:
235 if (e->payload.value && term->__shift)
237 vt100_scroll_down(term, term->phys_h / 2); // scroll for half screen
239 touch_repeat(term, e->payload.code, e->payload.value);
243 if (e->payload.value) // regular chars
244 vt100_add_key(term, e->payload.code);
245 touch_repeat(term, e->payload.code, e->payload.value);
254 LOG("vt100_redraw()");
261 //LOGl("Event = %d", e->payload.type);
272 // convert attributes to corresponding gfxbitmap_color_pix_t
273 static void attribs_to_colors(l4_int8_t a, gfxbitmap_color_pix_t *fg,
274 gfxbitmap_color_pix_t *bg)
278 unpack_attribs(a, &fg_i, &bg_i, &in);
279 *fg = libterm_get_color(in, fg_i);
280 *bg = libterm_get_color(in, bg_i);
283 // redraw whole screen
284 void vt100_redraw(termstate_t *term)
287 int old_x = 0, old_y = 0;
289 l4_int8_t old_attrib = 0;
291 gfxbitmap_color_pix_t fg, bg;
293 // LOGl("term = %p, text = %p, color = %p", term, term->text, term->color);
296 // correct y for vis offset
297 for (y = 0 - term->vis_off; y < term->phys_h - term->vis_off; y++)
299 for (x = 0; x < term->w; x++)
301 //vt100_redraw_xy(term, x, y);
303 // if we observe a change in attributes, send the
304 // accumulated string
305 if (s != NULL && old_attrib != term->attrib[xy2index(term, x, y)])
307 attribs_to_colors(old_attrib, &fg, &bg);
308 // correct y for vis offset
309 con_puts(term, old_x, old_y + term->vis_off, s,
310 xy2index(term, x, y) - old_index, fg, bg);
313 // start a new string
316 old_index = xy2index(term, x, y);
317 s = term->text + old_index;
318 old_attrib = term->attrib[old_index];
323 // care for end of line remainder strings
326 attribs_to_colors(old_attrib, &fg, &bg);
327 // correct y for vis offset
328 con_puts(term, old_x, old_y + term->vis_off, s,
329 xy2index(term, x - 1, y) - old_index + 1, fg, bg);
335 void vt100_redraw_xy(termstate_t *term, int x, int y)
337 gfxbitmap_color_pix_t fg, bg;
341 // if out of bound, do nothing
342 if (y + term->vis_off >= term->phys_h)
347 c = term->text + xy2index(term, x, y);
348 a = term->attrib[xy2index(term, x, y)];
349 attribs_to_colors(a, &fg, &bg);
350 // correct for moved vis
351 con_puts(term, x, y + term->vis_off, c, 1, fg, bg);
354 // vt100 backends, currently not implemented
355 void vt100_hide_cursor(termstate_t *term)
357 if (term->cursor_vis)
359 // if the cursor is in visible area...
360 if ( (term->cur_y + term->vis_off) <= term->phys_h )
362 int bg, fg, intensity;
363 int index = xy2index( term, term->cur_x, term->cur_y );
365 unpack_attribs( term->attrib[index], &fg, &bg, &intensity );
366 term->attrib[index] = pack_attribs( bg, fg, intensity );
368 // only redraw if cursor is visible
369 vt100_redraw_xy( term, term->cur_x, term->cur_y );
374 void vt100_show_cursor(termstate_t *term)
376 if (term->cursor_vis)
378 if ( (term->cur_y + term->vis_off) <= term->phys_h )
380 int bg, fg, intensity;
381 int index = xy2index( term, term->cur_x, term->cur_y );
383 unpack_attribs( term->attrib[index], &fg, &bg, &intensity );
384 term->attrib[index] = pack_attribs( bg, fg, intensity );
386 // only redraw if cursor is visible
387 vt100_redraw_xy( term, term->cur_x, term->cur_y );
393 static L4Re::Util::Object_registry term_registry;
401 Terminal::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
408 case L4::Meta::Protocol:
409 return L4::Util::handle_meta_request<L4::Vcon>(ios);
410 case L4::Irq::Protocol:
411 return Icu_svr::dispatch(obj, ios);
412 case L4::Vcon::Protocol:
415 return -L4_EBADPROTO;
421 if (op == L4_VCON_WRITE_OP)
424 = L4_UTCB_GENERIC_DATA_SIZE * sizeof(l4_utcb_mr()->mr[0]);
427 ios >> L4::ipc_buf_cp_in(buf, len);
429 //printf("%.*s\n", (int)len, buf);
432 vt100_write(term, buf, len);
434 L4Re::Env::env()->log()->printn(buf, len);
440 l4_umword_t size = op >> 16;
443 if (size > L4_UTCB_GENERIC_DATA_SIZE * sizeof(l4_utcb_mr()->mr[0]))
444 size = L4_UTCB_GENERIC_DATA_SIZE * sizeof(l4_utcb_mr()->mr[0]);
448 while (size && (c = vt100_trygetchar(term)) != -1)
456 // 1 << 31 that the other side should do a wait-for-irq again, we
457 // do this if we read -1 out of trygetchar
462 ios.put((char const *)_buf, size & ~(1UL << 31));
467 class Controller : public L4::Server_object
470 int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
474 Controller::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
481 case L4::Meta::Protocol:
482 return L4::Util::handle_meta_request<L4::Factory>(ios);
483 case L4::Factory::Protocol:
486 return -L4_EBADPROTO;
489 L4::Factory::Proto op;
494 case L4::Vcon::Protocol:
498 Terminal *t = new Terminal;
499 ios << term_registry.register_obj(t);
501 catch (L4::Runtime_error const &e)
505 catch (std::bad_alloc const &)
517 : public L4::Ipc_svr::Default_timeout,
518 public L4::Ipc_svr::Ignore_errors,
519 public L4::Ipc_svr::Compound_reply
521 void setup_wait(L4::Ipc_istream &istr, L4::Ipc_svr::Reply_mode)
524 istr << L4::Small_buf(rcv_cap().cap(), L4_RCV_ITEM_LOCAL_ID);
525 l4_utcb_br_u(istr.utcb())->bdr = 0;
529 static L4::Server<My_hooks> server(l4_utcb());
533 const char* error = init();
540 Event::Event event(ev_irq, event_handler, 0, 0xff);
541 if (!event.attached())
545 term_registry.register_obj(&_terminal, "term");
546 terminal = &_terminal;
547 if (!term_registry.register_obj(&_terminal, "term"))
549 printf("Terminal registration failed.\n");
556 if (!term_registry.register_obj(&ctrl, "terminal"))
558 printf("Terminal ctrl registration failed.\n");
563 server.loop(term_registry);