source: mainline/uspace/srv/hid/output/output.c@ 36aec61e

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 36aec61e was 1382446, checked in by Jiri Svoboda <jiri@…>, 5 years ago

Display device backend for output server

This provides console on a grahpical device, similar to the old kfb
backend. It talks to the userspace kfb driver, instead of mapping
the kfb directly. You can get graphical console by configuring
CONFIG_FB=y and CONFIG_WINSYS=n

  • Property mode set to 100644
File size: 11.2 KB
RevLine 
[6d5e378]1/*
2 * Copyright (c) 2011 Martin Decky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[4122410]29/** @addtogroup output
30 * @{
31 */
32
[6d5e378]33#include <errno.h>
[38d150e]34#include <stddef.h>
35#include <stdlib.h>
[6d5e378]36#include <macros.h>
37#include <as.h>
[2f6ad06]38#include <task.h>
[6d5e378]39#include <ipc/output.h>
[73d8600]40#include <config.h>
[6d5e378]41#include "port/ega.h"
[e53794c]42#include "port/chardev.h"
[1382446]43#include "port/ddev.h"
[6d5e378]44#include "output.h"
45
46#define MAX_COLS 128
47#define MAX_ROWS 128
48
49typedef struct {
50 link_t link;
[a35b458]51
[6d5e378]52 size_t size;
53 unsigned int flags;
54 void *data;
55} frontbuf_t;
56
57static LIST_INITIALIZE(outdevs);
58static LIST_INITIALIZE(frontbufs);
59
60outdev_t *outdev_register(outdev_ops_t *ops, void *data)
61{
62 assert(ops->get_dimensions);
[a35b458]63
[6d5e378]64 outdev_t *dev = (outdev_t *) malloc(sizeof(outdev_t));
65 if (dev == NULL)
66 return NULL;
[a35b458]67
[6d5e378]68 link_initialize(&dev->link);
[a35b458]69
[6d5e378]70 dev->ops = *ops;
71 dev->data = data;
[a35b458]72
[6d5e378]73 ops->get_dimensions(dev, &dev->cols, &dev->rows);
74 dev->backbuf = chargrid_create(dev->cols, dev->rows,
75 CHARGRID_FLAG_NONE);
76 if (dev->backbuf == NULL) {
77 free(dev);
78 return NULL;
79 }
[a35b458]80
[6d5e378]81 list_append(&dev->link, &outdevs);
82 return dev;
83}
84
[984a9ba]85static void srv_yield(ipc_call_t *icall)
[6d5e378]86{
[b7fd2a0]87 errno_t ret = EOK;
[a35b458]88
[feeac0d]89 list_foreach(outdevs, link, outdev_t, dev) {
[6d5e378]90 assert(dev->ops.yield);
[a35b458]91
[b7fd2a0]92 errno_t rc = dev->ops.yield(dev);
[6d5e378]93 if (rc != EOK)
94 ret = rc;
95 }
[a35b458]96
[984a9ba]97 async_answer_0(icall, ret);
[6d5e378]98}
99
[984a9ba]100static void srv_claim(ipc_call_t *icall)
[6d5e378]101{
[b7fd2a0]102 errno_t ret = EOK;
[a35b458]103
[feeac0d]104 list_foreach(outdevs, link, outdev_t, dev) {
[6d5e378]105 assert(dev->ops.claim);
[a35b458]106
[b7fd2a0]107 errno_t rc = dev->ops.claim(dev);
[6d5e378]108 if (rc != EOK)
109 ret = rc;
110 }
[a35b458]111
[984a9ba]112 async_answer_0(icall, ret);
[6d5e378]113}
114
[984a9ba]115static void srv_get_dimensions(ipc_call_t *icall)
[6d5e378]116{
117 sysarg_t cols = MAX_COLS;
118 sysarg_t rows = MAX_ROWS;
[a35b458]119
[feeac0d]120 list_foreach(outdevs, link, outdev_t, dev) {
[6d5e378]121 cols = min(cols, dev->cols);
122 rows = min(rows, dev->rows);
123 }
[a35b458]124
[984a9ba]125 async_answer_2(icall, EOK, cols, rows);
[6d5e378]126}
127
[984a9ba]128static void srv_get_caps(ipc_call_t *icall)
[6d5e378]129{
130 console_caps_t caps = 0;
[a35b458]131
[feeac0d]132 list_foreach(outdevs, link, outdev_t, dev) {
[6d5e378]133 assert(dev->ops.get_caps);
[a35b458]134
[6d5e378]135 caps |= dev->ops.get_caps(dev);
136 }
[a35b458]137
[984a9ba]138 async_answer_1(icall, EOK, caps);
[6d5e378]139}
140
[984a9ba]141static frontbuf_t *resolve_frontbuf(sysarg_t handle, ipc_call_t *icall)
[6d5e378]142{
143 frontbuf_t *frontbuf = NULL;
[feeac0d]144 list_foreach(frontbufs, link, frontbuf_t, cur) {
[6d5e378]145 if (cur == (frontbuf_t *) handle) {
146 frontbuf = cur;
147 break;
148 }
149 }
[a35b458]150
[6d5e378]151 if (frontbuf == NULL) {
[984a9ba]152 async_answer_0(icall, ENOENT);
[6d5e378]153 return NULL;
154 }
[a35b458]155
[6d5e378]156 return frontbuf;
157}
158
[984a9ba]159static void srv_frontbuf_create(ipc_call_t *icall)
[6d5e378]160{
161 frontbuf_t *frontbuf = (frontbuf_t *) malloc(sizeof(frontbuf_t));
162 if (frontbuf == NULL) {
[984a9ba]163 async_answer_0(icall, ENOMEM);
[6d5e378]164 return;
165 }
[a35b458]166
[6d5e378]167 link_initialize(&frontbuf->link);
[a35b458]168
[984a9ba]169 ipc_call_t call;
170 if (!async_share_out_receive(&call, &frontbuf->size,
[6d5e378]171 &frontbuf->flags)) {
172 free(frontbuf);
[984a9ba]173 async_answer_0(icall, EINVAL);
[6d5e378]174 return;
175 }
[a35b458]176
[984a9ba]177 errno_t rc = async_share_out_finalize(&call, &frontbuf->data);
[6d5e378]178 if ((rc != EOK) || (frontbuf->data == AS_MAP_FAILED)) {
179 free(frontbuf);
[984a9ba]180 async_answer_0(icall, ENOMEM);
[6d5e378]181 return;
182 }
[a35b458]183
[6d5e378]184 list_append(&frontbuf->link, &frontbufs);
[984a9ba]185 async_answer_1(icall, EOK, (sysarg_t) frontbuf);
[6d5e378]186}
187
[984a9ba]188static void srv_frontbuf_destroy(ipc_call_t *icall)
[6d5e378]189{
[fafb8e5]190 frontbuf_t *frontbuf = resolve_frontbuf(ipc_get_arg1(icall), icall);
[6d5e378]191 if (frontbuf == NULL)
192 return;
[a35b458]193
[6d5e378]194 list_remove(&frontbuf->link);
195 as_area_destroy(frontbuf->data);
196 free(frontbuf);
[a35b458]197
[984a9ba]198 async_answer_0(icall, EOK);
[6d5e378]199}
200
[984a9ba]201static void srv_cursor_update(ipc_call_t *icall)
[6d5e378]202{
[fafb8e5]203 frontbuf_t *frontbuf = resolve_frontbuf(ipc_get_arg1(icall), icall);
[6d5e378]204 if (frontbuf == NULL)
205 return;
[a35b458]206
[6d5e378]207 chargrid_t *buf = (chargrid_t *) frontbuf->data;
208 bool visible = chargrid_get_cursor_visibility(buf);
[a35b458]209
[6d5e378]210 sysarg_t col;
211 sysarg_t row;
212 chargrid_get_cursor(buf, &col, &row);
[a35b458]213
[feeac0d]214 list_foreach(outdevs, link, outdev_t, dev) {
[6d5e378]215 assert(dev->ops.cursor_update);
[a35b458]216
[6d5e378]217 sysarg_t prev_col;
218 sysarg_t prev_row;
219 chargrid_get_cursor(dev->backbuf, &prev_col, &prev_row);
[a35b458]220
[6d5e378]221 chargrid_set_cursor(dev->backbuf, col, row);
222 chargrid_set_cursor_visibility(dev->backbuf, visible);
[a35b458]223
[6d5e378]224 dev->ops.cursor_update(dev, prev_col, prev_row, col, row,
225 visible);
[bbc6277]226 dev->ops.flush(dev);
227
[6d5e378]228 }
[a35b458]229
[984a9ba]230 async_answer_0(icall, EOK);
[6d5e378]231}
232
[984a9ba]233static void srv_set_style(ipc_call_t *icall)
[6d5e378]234{
[feeac0d]235 list_foreach(outdevs, link, outdev_t, dev) {
[6d5e378]236 dev->attrs.type = CHAR_ATTR_STYLE;
237 dev->attrs.val.style =
[fafb8e5]238 (console_style_t) ipc_get_arg1(icall);
[6d5e378]239 }
[a35b458]240
[984a9ba]241 async_answer_0(icall, EOK);
[6d5e378]242}
243
[984a9ba]244static void srv_set_color(ipc_call_t *icall)
[6d5e378]245{
[feeac0d]246 list_foreach(outdevs, link, outdev_t, dev) {
[6d5e378]247 dev->attrs.type = CHAR_ATTR_INDEX;
248 dev->attrs.val.index.bgcolor =
[fafb8e5]249 (console_color_t) ipc_get_arg1(icall);
[6d5e378]250 dev->attrs.val.index.fgcolor =
[fafb8e5]251 (console_color_t) ipc_get_arg2(icall);
[6d5e378]252 dev->attrs.val.index.attr =
[fafb8e5]253 (console_color_attr_t) ipc_get_arg3(icall);
[6d5e378]254 }
[a35b458]255
[984a9ba]256 async_answer_0(icall, EOK);
[6d5e378]257}
258
[984a9ba]259static void srv_set_rgb_color(ipc_call_t *icall)
[6d5e378]260{
[feeac0d]261 list_foreach(outdevs, link, outdev_t, dev) {
[6d5e378]262 dev->attrs.type = CHAR_ATTR_RGB;
[fafb8e5]263 dev->attrs.val.rgb.bgcolor = ipc_get_arg1(icall);
264 dev->attrs.val.rgb.fgcolor = ipc_get_arg2(icall);
[6d5e378]265 }
[a35b458]266
[984a9ba]267 async_answer_0(icall, EOK);
[6d5e378]268}
269
270static bool srv_update_scroll(outdev_t *dev, chargrid_t *buf)
271{
272 assert(dev->ops.char_update);
[a35b458]273
[6d5e378]274 sysarg_t top_row = chargrid_get_top_row(buf);
[a35b458]275
[6d5e378]276 if (dev->top_row == top_row)
277 return false;
[a35b458]278
[6d5e378]279 dev->top_row = top_row;
[a35b458]280
[6d5e378]281 for (sysarg_t y = 0; y < dev->rows; y++) {
282 for (sysarg_t x = 0; x < dev->cols; x++) {
283 charfield_t *front_field =
284 chargrid_charfield_at(buf, x, y);
285 charfield_t *back_field =
286 chargrid_charfield_at(dev->backbuf, x, y);
287 bool update = false;
[a35b458]288
[6d5e378]289 if (front_field->ch != back_field->ch) {
290 back_field->ch = front_field->ch;
291 update = true;
292 }
[a35b458]293
[6d5e378]294 if (!attrs_same(front_field->attrs, back_field->attrs)) {
295 back_field->attrs = front_field->attrs;
296 update = true;
297 }
[a35b458]298
[6d5e378]299 front_field->flags &= ~CHAR_FLAG_DIRTY;
[a35b458]300
[6d5e378]301 if (update)
302 dev->ops.char_update(dev, x, y);
303 }
304 }
[a35b458]305
[6d5e378]306 return true;
307}
308
[984a9ba]309static void srv_update(ipc_call_t *icall)
[6d5e378]310{
[fafb8e5]311 frontbuf_t *frontbuf = resolve_frontbuf(ipc_get_arg1(icall), icall);
[6d5e378]312 if (frontbuf == NULL)
313 return;
[a35b458]314
[6d5e378]315 chargrid_t *buf = (chargrid_t *) frontbuf->data;
[a35b458]316
[feeac0d]317 list_foreach(outdevs, link, outdev_t, dev) {
[6d5e378]318 assert(dev->ops.char_update);
[a35b458]319
[6d5e378]320 if (srv_update_scroll(dev, buf))
321 continue;
[a35b458]322
[6d5e378]323 for (sysarg_t y = 0; y < dev->rows; y++) {
324 for (sysarg_t x = 0; x < dev->cols; x++) {
325 charfield_t *front_field =
326 chargrid_charfield_at(buf, x, y);
327 charfield_t *back_field =
328 chargrid_charfield_at(dev->backbuf, x, y);
329 bool update = false;
[a35b458]330
[6d5e378]331 if ((front_field->flags & CHAR_FLAG_DIRTY) ==
332 CHAR_FLAG_DIRTY) {
333 if (front_field->ch != back_field->ch) {
334 back_field->ch = front_field->ch;
335 update = true;
336 }
[a35b458]337
[6d5e378]338 if (!attrs_same(front_field->attrs,
339 back_field->attrs)) {
340 back_field->attrs = front_field->attrs;
341 update = true;
342 }
[a35b458]343
[6d5e378]344 front_field->flags &= ~CHAR_FLAG_DIRTY;
345 }
[a35b458]346
[6d5e378]347 if (update)
348 dev->ops.char_update(dev, x, y);
349 }
350 }
[a35b458]351
[bbc6277]352 dev->ops.flush(dev);
[6d5e378]353 }
[a35b458]354
[984a9ba]355 async_answer_0(icall, EOK);
[6d5e378]356}
357
[984a9ba]358static void srv_damage(ipc_call_t *icall)
[6d5e378]359{
[fafb8e5]360 frontbuf_t *frontbuf = resolve_frontbuf(ipc_get_arg1(icall), icall);
[6d5e378]361 if (frontbuf == NULL)
362 return;
[a35b458]363
[6d5e378]364 chargrid_t *buf = (chargrid_t *) frontbuf->data;
[a35b458]365
[feeac0d]366 list_foreach(outdevs, link, outdev_t, dev) {
[6d5e378]367 assert(dev->ops.char_update);
[a35b458]368
[6d5e378]369 if (srv_update_scroll(dev, buf))
370 continue;
[a35b458]371
[fafb8e5]372 sysarg_t col = ipc_get_arg2(icall);
373 sysarg_t row = ipc_get_arg3(icall);
[a35b458]374
[fafb8e5]375 sysarg_t cols = ipc_get_arg4(icall);
376 sysarg_t rows = ipc_get_arg5(icall);
[a35b458]377
[6d5e378]378 for (sysarg_t y = 0; y < rows; y++) {
379 for (sysarg_t x = 0; x < cols; x++) {
380 charfield_t *front_field =
381 chargrid_charfield_at(buf, col + x, row + y);
382 charfield_t *back_field =
383 chargrid_charfield_at(dev->backbuf, col + x, row + y);
[a35b458]384
[6d5e378]385 back_field->ch = front_field->ch;
386 back_field->attrs = front_field->attrs;
387 front_field->flags &= ~CHAR_FLAG_DIRTY;
388 dev->ops.char_update(dev, col + x, row + y);
389 }
390 }
[bbc6277]391 dev->ops.flush(dev);
392
[6d5e378]393 }
[984a9ba]394
395 async_answer_0(icall, EOK);
[6d5e378]396}
397
[984a9ba]398static void client_connection(ipc_call_t *icall, void *arg)
[6d5e378]399{
400 /* Accept the connection */
[beb83c1]401 async_accept_0(icall);
[a35b458]402
[6d5e378]403 while (true) {
404 ipc_call_t call;
[984a9ba]405 async_get_call(&call);
[a35b458]406
[fafb8e5]407 if (!ipc_get_imethod(&call)) {
[984a9ba]408 async_answer_0(&call, EOK);
[6d5e378]409 break;
410 }
[a35b458]411
[fafb8e5]412 switch (ipc_get_imethod(&call)) {
[6feb444]413 case OUTPUT_YIELD:
[984a9ba]414 srv_yield(&call);
[6feb444]415 break;
416 case OUTPUT_CLAIM:
[984a9ba]417 srv_claim(&call);
[6feb444]418 break;
419 case OUTPUT_GET_DIMENSIONS:
[984a9ba]420 srv_get_dimensions(&call);
[6feb444]421 break;
422 case OUTPUT_GET_CAPS:
[984a9ba]423 srv_get_caps(&call);
[6feb444]424 break;
[a35b458]425
[6feb444]426 case OUTPUT_FRONTBUF_CREATE:
[984a9ba]427 srv_frontbuf_create(&call);
[6feb444]428 break;
429 case OUTPUT_FRONTBUF_DESTROY:
[984a9ba]430 srv_frontbuf_destroy(&call);
[6feb444]431 break;
[a35b458]432
[6feb444]433 case OUTPUT_CURSOR_UPDATE:
[984a9ba]434 srv_cursor_update(&call);
[6feb444]435 break;
436 case OUTPUT_SET_STYLE:
[984a9ba]437 srv_set_style(&call);
[6feb444]438 break;
439 case OUTPUT_SET_COLOR:
[984a9ba]440 srv_set_color(&call);
[6feb444]441 break;
442 case OUTPUT_SET_RGB_COLOR:
[984a9ba]443 srv_set_rgb_color(&call);
[6feb444]444 break;
445 case OUTPUT_UPDATE:
[984a9ba]446 srv_update(&call);
[6feb444]447 break;
448 case OUTPUT_DAMAGE:
[984a9ba]449 srv_damage(&call);
[6feb444]450 break;
[a35b458]451
[6feb444]452 default:
[984a9ba]453 async_answer_0(&call, EINVAL);
[6d5e378]454 }
455 }
456}
457
458static void usage(char *name)
459{
460 printf("Usage: %s <service_name>\n", name);
461}
462
463int main(int argc, char *argv[])
464{
465 if (argc < 2) {
466 usage(argv[0]);
467 return 1;
468 }
[a35b458]469
[6d5e378]470 printf("%s: HelenOS output service\n", NAME);
[a35b458]471
[6d5e378]472 /* Register server */
[b688fd8]473 async_set_fallback_port_handler(client_connection, NULL);
[b7fd2a0]474 errno_t rc = loc_server_register(NAME);
[6d5e378]475 if (rc != EOK) {
476 printf("%s: Unable to register driver\n", NAME);
477 return rc;
478 }
[a35b458]479
[6d5e378]480 service_id_t service_id;
481 rc = loc_service_register(argv[1], &service_id);
482 if (rc != EOK) {
483 printf("%s: Unable to register service %s\n", NAME, argv[1]);
484 return rc;
485 }
[a35b458]486
[73d8600]487 if (!config_key_exists("console")) {
488 ega_init();
[1382446]489#if defined(CONFIG_FB) && !defined(CONFIG_WINSYS)
490 /*
491 * NOTE: We don't have a good way of detecting the absence
492 * of a KFB display device at run time because of the
493 * asunchronous nature of device discovery
494 */
495 output_ddev_init();
496#endif
[73d8600]497 }
[a35b458]498
[9940ce0]499 chardev_init();
[a35b458]500
[6d5e378]501 printf("%s: Accepting connections\n", NAME);
502 task_retval(0);
503 async_manager();
[a35b458]504
[6d5e378]505 /* Never reached */
506 return 0;
507}
[4122410]508
509/** @}
510 */
Note: See TracBrowser for help on using the repository browser.