source: mainline/uspace/srv/hid/output/output.c@ da680b4b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since da680b4b was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 10.9 KB
Line 
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
29#include <errno.h>
30#include <stddef.h>
31#include <stdlib.h>
32#include <macros.h>
33#include <as.h>
34#include <task.h>
35#include <ipc/output.h>
36#include <config.h>
37#include "port/ega.h"
38#include "port/chardev.h"
39#include "output.h"
40
41#define MAX_COLS 128
42#define MAX_ROWS 128
43
44typedef struct {
45 link_t link;
46
47 size_t size;
48 unsigned int flags;
49 void *data;
50} frontbuf_t;
51
52static LIST_INITIALIZE(outdevs);
53static LIST_INITIALIZE(frontbufs);
54
55outdev_t *outdev_register(outdev_ops_t *ops, void *data)
56{
57 assert(ops->get_dimensions);
58
59 outdev_t *dev = (outdev_t *) malloc(sizeof(outdev_t));
60 if (dev == NULL)
61 return NULL;
62
63 link_initialize(&dev->link);
64
65 dev->ops = *ops;
66 dev->data = data;
67
68 ops->get_dimensions(dev, &dev->cols, &dev->rows);
69 dev->backbuf = chargrid_create(dev->cols, dev->rows,
70 CHARGRID_FLAG_NONE);
71 if (dev->backbuf == NULL) {
72 free(dev);
73 return NULL;
74 }
75
76 list_append(&dev->link, &outdevs);
77 return dev;
78}
79
80static void srv_yield(ipc_call_t *icall)
81{
82 errno_t ret = EOK;
83
84 list_foreach(outdevs, link, outdev_t, dev) {
85 assert(dev->ops.yield);
86
87 errno_t rc = dev->ops.yield(dev);
88 if (rc != EOK)
89 ret = rc;
90 }
91
92 async_answer_0(icall, ret);
93}
94
95static void srv_claim(ipc_call_t *icall)
96{
97 errno_t ret = EOK;
98
99 list_foreach(outdevs, link, outdev_t, dev) {
100 assert(dev->ops.claim);
101
102 errno_t rc = dev->ops.claim(dev);
103 if (rc != EOK)
104 ret = rc;
105 }
106
107 async_answer_0(icall, ret);
108}
109
110static void srv_get_dimensions(ipc_call_t *icall)
111{
112 sysarg_t cols = MAX_COLS;
113 sysarg_t rows = MAX_ROWS;
114
115 list_foreach(outdevs, link, outdev_t, dev) {
116 cols = min(cols, dev->cols);
117 rows = min(rows, dev->rows);
118 }
119
120 async_answer_2(icall, EOK, cols, rows);
121}
122
123static void srv_get_caps(ipc_call_t *icall)
124{
125 console_caps_t caps = 0;
126
127 list_foreach(outdevs, link, outdev_t, dev) {
128 assert(dev->ops.get_caps);
129
130 caps |= dev->ops.get_caps(dev);
131 }
132
133 async_answer_1(icall, EOK, caps);
134}
135
136static frontbuf_t *resolve_frontbuf(sysarg_t handle, ipc_call_t *icall)
137{
138 frontbuf_t *frontbuf = NULL;
139 list_foreach(frontbufs, link, frontbuf_t, cur) {
140 if (cur == (frontbuf_t *) handle) {
141 frontbuf = cur;
142 break;
143 }
144 }
145
146 if (frontbuf == NULL) {
147 async_answer_0(icall, ENOENT);
148 return NULL;
149 }
150
151 return frontbuf;
152}
153
154static void srv_frontbuf_create(ipc_call_t *icall)
155{
156 frontbuf_t *frontbuf = (frontbuf_t *) malloc(sizeof(frontbuf_t));
157 if (frontbuf == NULL) {
158 async_answer_0(icall, ENOMEM);
159 return;
160 }
161
162 link_initialize(&frontbuf->link);
163
164 ipc_call_t call;
165 if (!async_share_out_receive(&call, &frontbuf->size,
166 &frontbuf->flags)) {
167 free(frontbuf);
168 async_answer_0(icall, EINVAL);
169 return;
170 }
171
172 errno_t rc = async_share_out_finalize(&call, &frontbuf->data);
173 if ((rc != EOK) || (frontbuf->data == AS_MAP_FAILED)) {
174 free(frontbuf);
175 async_answer_0(icall, ENOMEM);
176 return;
177 }
178
179 list_append(&frontbuf->link, &frontbufs);
180 async_answer_1(icall, EOK, (sysarg_t) frontbuf);
181}
182
183static void srv_frontbuf_destroy(ipc_call_t *icall)
184{
185 frontbuf_t *frontbuf = resolve_frontbuf(IPC_GET_ARG1(*icall), icall);
186 if (frontbuf == NULL)
187 return;
188
189 list_remove(&frontbuf->link);
190 as_area_destroy(frontbuf->data);
191 free(frontbuf);
192
193 async_answer_0(icall, EOK);
194}
195
196static void srv_cursor_update(ipc_call_t *icall)
197{
198 frontbuf_t *frontbuf = resolve_frontbuf(IPC_GET_ARG1(*icall), icall);
199 if (frontbuf == NULL)
200 return;
201
202 chargrid_t *buf = (chargrid_t *) frontbuf->data;
203 bool visible = chargrid_get_cursor_visibility(buf);
204
205 sysarg_t col;
206 sysarg_t row;
207 chargrid_get_cursor(buf, &col, &row);
208
209 list_foreach(outdevs, link, outdev_t, dev) {
210 assert(dev->ops.cursor_update);
211
212 sysarg_t prev_col;
213 sysarg_t prev_row;
214 chargrid_get_cursor(dev->backbuf, &prev_col, &prev_row);
215
216 chargrid_set_cursor(dev->backbuf, col, row);
217 chargrid_set_cursor_visibility(dev->backbuf, visible);
218
219 dev->ops.cursor_update(dev, prev_col, prev_row, col, row,
220 visible);
221 dev->ops.flush(dev);
222
223 }
224
225 async_answer_0(icall, EOK);
226}
227
228static void srv_set_style(ipc_call_t *icall)
229{
230 list_foreach(outdevs, link, outdev_t, dev) {
231 dev->attrs.type = CHAR_ATTR_STYLE;
232 dev->attrs.val.style =
233 (console_style_t) IPC_GET_ARG1(*icall);
234 }
235
236 async_answer_0(icall, EOK);
237}
238
239static void srv_set_color(ipc_call_t *icall)
240{
241 list_foreach(outdevs, link, outdev_t, dev) {
242 dev->attrs.type = CHAR_ATTR_INDEX;
243 dev->attrs.val.index.bgcolor =
244 (console_color_t) IPC_GET_ARG1(*icall);
245 dev->attrs.val.index.fgcolor =
246 (console_color_t) IPC_GET_ARG2(*icall);
247 dev->attrs.val.index.attr =
248 (console_color_attr_t) IPC_GET_ARG3(*icall);
249 }
250
251 async_answer_0(icall, EOK);
252}
253
254static void srv_set_rgb_color(ipc_call_t *icall)
255{
256 list_foreach(outdevs, link, outdev_t, dev) {
257 dev->attrs.type = CHAR_ATTR_RGB;
258 dev->attrs.val.rgb.bgcolor = IPC_GET_ARG1(*icall);
259 dev->attrs.val.rgb.fgcolor = IPC_GET_ARG2(*icall);
260 }
261
262 async_answer_0(icall, EOK);
263}
264
265static bool srv_update_scroll(outdev_t *dev, chargrid_t *buf)
266{
267 assert(dev->ops.char_update);
268
269 sysarg_t top_row = chargrid_get_top_row(buf);
270
271 if (dev->top_row == top_row)
272 return false;
273
274 dev->top_row = top_row;
275
276 for (sysarg_t y = 0; y < dev->rows; y++) {
277 for (sysarg_t x = 0; x < dev->cols; x++) {
278 charfield_t *front_field =
279 chargrid_charfield_at(buf, x, y);
280 charfield_t *back_field =
281 chargrid_charfield_at(dev->backbuf, x, y);
282 bool update = false;
283
284 if (front_field->ch != back_field->ch) {
285 back_field->ch = front_field->ch;
286 update = true;
287 }
288
289 if (!attrs_same(front_field->attrs, back_field->attrs)) {
290 back_field->attrs = front_field->attrs;
291 update = true;
292 }
293
294 front_field->flags &= ~CHAR_FLAG_DIRTY;
295
296 if (update)
297 dev->ops.char_update(dev, x, y);
298 }
299 }
300
301 return true;
302}
303
304static void srv_update(ipc_call_t *icall)
305{
306 frontbuf_t *frontbuf = resolve_frontbuf(IPC_GET_ARG1(*icall), icall);
307 if (frontbuf == NULL)
308 return;
309
310 chargrid_t *buf = (chargrid_t *) frontbuf->data;
311
312 list_foreach(outdevs, link, outdev_t, dev) {
313 assert(dev->ops.char_update);
314
315 if (srv_update_scroll(dev, buf))
316 continue;
317
318 for (sysarg_t y = 0; y < dev->rows; y++) {
319 for (sysarg_t x = 0; x < dev->cols; x++) {
320 charfield_t *front_field =
321 chargrid_charfield_at(buf, x, y);
322 charfield_t *back_field =
323 chargrid_charfield_at(dev->backbuf, x, y);
324 bool update = false;
325
326 if ((front_field->flags & CHAR_FLAG_DIRTY) ==
327 CHAR_FLAG_DIRTY) {
328 if (front_field->ch != back_field->ch) {
329 back_field->ch = front_field->ch;
330 update = true;
331 }
332
333 if (!attrs_same(front_field->attrs,
334 back_field->attrs)) {
335 back_field->attrs = front_field->attrs;
336 update = true;
337 }
338
339 front_field->flags &= ~CHAR_FLAG_DIRTY;
340 }
341
342 if (update)
343 dev->ops.char_update(dev, x, y);
344 }
345 }
346
347 dev->ops.flush(dev);
348 }
349
350 async_answer_0(icall, EOK);
351}
352
353static void srv_damage(ipc_call_t *icall)
354{
355 frontbuf_t *frontbuf = resolve_frontbuf(IPC_GET_ARG1(*icall), icall);
356 if (frontbuf == NULL)
357 return;
358
359 chargrid_t *buf = (chargrid_t *) frontbuf->data;
360
361 list_foreach(outdevs, link, outdev_t, dev) {
362 assert(dev->ops.char_update);
363
364 if (srv_update_scroll(dev, buf))
365 continue;
366
367 sysarg_t col = IPC_GET_ARG2(*icall);
368 sysarg_t row = IPC_GET_ARG3(*icall);
369
370 sysarg_t cols = IPC_GET_ARG4(*icall);
371 sysarg_t rows = IPC_GET_ARG5(*icall);
372
373 for (sysarg_t y = 0; y < rows; y++) {
374 for (sysarg_t x = 0; x < cols; x++) {
375 charfield_t *front_field =
376 chargrid_charfield_at(buf, col + x, row + y);
377 charfield_t *back_field =
378 chargrid_charfield_at(dev->backbuf, col + x, row + y);
379
380 back_field->ch = front_field->ch;
381 back_field->attrs = front_field->attrs;
382 front_field->flags &= ~CHAR_FLAG_DIRTY;
383 dev->ops.char_update(dev, col + x, row + y);
384 }
385 }
386 dev->ops.flush(dev);
387
388 }
389
390 async_answer_0(icall, EOK);
391}
392
393static void client_connection(ipc_call_t *icall, void *arg)
394{
395 /* Accept the connection */
396 async_answer_0(icall, EOK);
397
398 while (true) {
399 ipc_call_t call;
400 async_get_call(&call);
401
402 if (!IPC_GET_IMETHOD(call)) {
403 async_answer_0(&call, EOK);
404 break;
405 }
406
407 switch (IPC_GET_IMETHOD(call)) {
408 case OUTPUT_YIELD:
409 srv_yield(&call);
410 break;
411 case OUTPUT_CLAIM:
412 srv_claim(&call);
413 break;
414 case OUTPUT_GET_DIMENSIONS:
415 srv_get_dimensions(&call);
416 break;
417 case OUTPUT_GET_CAPS:
418 srv_get_caps(&call);
419 break;
420
421 case OUTPUT_FRONTBUF_CREATE:
422 srv_frontbuf_create(&call);
423 break;
424 case OUTPUT_FRONTBUF_DESTROY:
425 srv_frontbuf_destroy(&call);
426 break;
427
428 case OUTPUT_CURSOR_UPDATE:
429 srv_cursor_update(&call);
430 break;
431 case OUTPUT_SET_STYLE:
432 srv_set_style(&call);
433 break;
434 case OUTPUT_SET_COLOR:
435 srv_set_color(&call);
436 break;
437 case OUTPUT_SET_RGB_COLOR:
438 srv_set_rgb_color(&call);
439 break;
440 case OUTPUT_UPDATE:
441 srv_update(&call);
442 break;
443 case OUTPUT_DAMAGE:
444 srv_damage(&call);
445 break;
446
447 default:
448 async_answer_0(&call, EINVAL);
449 }
450 }
451}
452
453static void usage(char *name)
454{
455 printf("Usage: %s <service_name>\n", name);
456}
457
458int main(int argc, char *argv[])
459{
460 if (argc < 2) {
461 usage(argv[0]);
462 return 1;
463 }
464
465 printf("%s: HelenOS output service\n", NAME);
466
467 /* Register server */
468 async_set_fallback_port_handler(client_connection, NULL);
469 errno_t rc = loc_server_register(NAME);
470 if (rc != EOK) {
471 printf("%s: Unable to register driver\n", NAME);
472 return rc;
473 }
474
475 service_id_t service_id;
476 rc = loc_service_register(argv[1], &service_id);
477 if (rc != EOK) {
478 printf("%s: Unable to register service %s\n", NAME, argv[1]);
479 return rc;
480 }
481
482 if (!config_key_exists("console")) {
483 ega_init();
484 }
485
486 chardev_init();
487
488 printf("%s: Accepting connections\n", NAME);
489 task_retval(0);
490 async_manager();
491
492 /* Never reached */
493 return 0;
494}
Note: See TracBrowser for help on using the repository browser.