source: mainline/uspace/srv/hid/output/output.c@ 53e3950

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

gradually introduce async ports, initial phase

The initial phase is to reimplement the traditional async client connections as an untyped fallback port. This creates the possibility to introduce ports typed by interface type gradually in later changesets.

  • Property mode set to 100644
File size: 11.2 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 <sys/types.h>
30#include <errno.h>
31#include <malloc.h>
32#include <macros.h>
33#include <as.h>
34#include <ipc/output.h>
35#include "port/ega.h"
36#include "port/kchar.h"
37#include "port/niagara.h"
38#include "port/ski.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_callid_t iid, ipc_call_t *icall)
81{
82 int ret = EOK;
83
84 list_foreach(outdevs, link, outdev_t, dev) {
85 assert(dev->ops.yield);
86
87 int rc = dev->ops.yield(dev);
88 if (rc != EOK)
89 ret = rc;
90 }
91
92 async_answer_0(iid, ret);
93}
94
95static void srv_claim(ipc_callid_t iid, ipc_call_t *icall)
96{
97 int ret = EOK;
98
99 list_foreach(outdevs, link, outdev_t, dev) {
100 assert(dev->ops.claim);
101
102 int rc = dev->ops.claim(dev);
103 if (rc != EOK)
104 ret = rc;
105 }
106
107 async_answer_0(iid, ret);
108}
109
110static void srv_get_dimensions(ipc_callid_t iid, 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(iid, EOK, cols, rows);
121}
122
123static void srv_get_caps(ipc_callid_t iid, 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(iid, EOK, caps);
134}
135
136static frontbuf_t *resolve_frontbuf(sysarg_t handle, ipc_callid_t iid)
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(iid, ENOENT);
148 return NULL;
149 }
150
151 return frontbuf;
152}
153
154static void srv_frontbuf_create(ipc_callid_t iid, ipc_call_t *icall)
155{
156 frontbuf_t *frontbuf = (frontbuf_t *) malloc(sizeof(frontbuf_t));
157 if (frontbuf == NULL) {
158 async_answer_0(iid, ENOMEM);
159 return;
160 }
161
162 link_initialize(&frontbuf->link);
163
164 ipc_callid_t callid;
165 if (!async_share_out_receive(&callid, &frontbuf->size,
166 &frontbuf->flags)) {
167 free(frontbuf);
168 async_answer_0(iid, EINVAL);
169 return;
170 }
171
172 int rc = async_share_out_finalize(callid, &frontbuf->data);
173 if ((rc != EOK) || (frontbuf->data == AS_MAP_FAILED)) {
174 free(frontbuf);
175 async_answer_0(iid, ENOMEM);
176 return;
177 }
178
179 list_append(&frontbuf->link, &frontbufs);
180 async_answer_1(iid, EOK, (sysarg_t) frontbuf);
181}
182
183static void srv_frontbuf_destroy(ipc_callid_t iid, ipc_call_t *icall)
184{
185 frontbuf_t *frontbuf = resolve_frontbuf(IPC_GET_ARG1(*icall), iid);
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(iid, EOK);
194}
195
196static void srv_cursor_update(ipc_callid_t iid, ipc_call_t *icall)
197{
198 frontbuf_t *frontbuf = resolve_frontbuf(IPC_GET_ARG1(*icall), iid);
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 }
222
223 async_answer_0(iid, EOK);
224}
225
226static void srv_set_style(ipc_callid_t iid, ipc_call_t *icall)
227{
228 list_foreach(outdevs, link, outdev_t, dev) {
229 dev->attrs.type = CHAR_ATTR_STYLE;
230 dev->attrs.val.style =
231 (console_style_t) IPC_GET_ARG1(*icall);
232 }
233
234 async_answer_0(iid, EOK);
235}
236
237static void srv_set_color(ipc_callid_t iid, ipc_call_t *icall)
238{
239 list_foreach(outdevs, link, outdev_t, dev) {
240 dev->attrs.type = CHAR_ATTR_INDEX;
241 dev->attrs.val.index.bgcolor =
242 (console_color_t) IPC_GET_ARG1(*icall);
243 dev->attrs.val.index.fgcolor =
244 (console_color_t) IPC_GET_ARG2(*icall);
245 dev->attrs.val.index.attr =
246 (console_color_attr_t) IPC_GET_ARG3(*icall);
247 }
248
249 async_answer_0(iid, EOK);
250}
251
252static void srv_set_rgb_color(ipc_callid_t iid, ipc_call_t *icall)
253{
254 list_foreach(outdevs, link, outdev_t, dev) {
255 dev->attrs.type = CHAR_ATTR_RGB;
256 dev->attrs.val.rgb.bgcolor = IPC_GET_ARG1(*icall);
257 dev->attrs.val.rgb.fgcolor = IPC_GET_ARG2(*icall);
258 }
259
260 async_answer_0(iid, EOK);
261}
262
263static bool srv_update_scroll(outdev_t *dev, chargrid_t *buf)
264{
265 assert(dev->ops.char_update);
266
267 sysarg_t top_row = chargrid_get_top_row(buf);
268
269 if (dev->top_row == top_row)
270 return false;
271
272 dev->top_row = top_row;
273
274 for (sysarg_t y = 0; y < dev->rows; y++) {
275 for (sysarg_t x = 0; x < dev->cols; x++) {
276 charfield_t *front_field =
277 chargrid_charfield_at(buf, x, y);
278 charfield_t *back_field =
279 chargrid_charfield_at(dev->backbuf, x, y);
280 bool update = false;
281
282 if (front_field->ch != back_field->ch) {
283 back_field->ch = front_field->ch;
284 update = true;
285 }
286
287 if (!attrs_same(front_field->attrs, back_field->attrs)) {
288 back_field->attrs = front_field->attrs;
289 update = true;
290 }
291
292 front_field->flags &= ~CHAR_FLAG_DIRTY;
293
294 if (update)
295 dev->ops.char_update(dev, x, y);
296 }
297 }
298
299 return true;
300}
301
302static void srv_update(ipc_callid_t iid, ipc_call_t *icall)
303{
304 frontbuf_t *frontbuf = resolve_frontbuf(IPC_GET_ARG1(*icall), iid);
305 if (frontbuf == NULL)
306 return;
307
308 chargrid_t *buf = (chargrid_t *) frontbuf->data;
309
310 list_foreach(outdevs, link, outdev_t, dev) {
311 assert(dev->ops.char_update);
312
313 if (srv_update_scroll(dev, buf))
314 continue;
315
316 for (sysarg_t y = 0; y < dev->rows; y++) {
317 for (sysarg_t x = 0; x < dev->cols; x++) {
318 charfield_t *front_field =
319 chargrid_charfield_at(buf, x, y);
320 charfield_t *back_field =
321 chargrid_charfield_at(dev->backbuf, x, y);
322 bool update = false;
323
324 if ((front_field->flags & CHAR_FLAG_DIRTY) ==
325 CHAR_FLAG_DIRTY) {
326 if (front_field->ch != back_field->ch) {
327 back_field->ch = front_field->ch;
328 update = true;
329 }
330
331 if (!attrs_same(front_field->attrs,
332 back_field->attrs)) {
333 back_field->attrs = front_field->attrs;
334 update = true;
335 }
336
337 front_field->flags &= ~CHAR_FLAG_DIRTY;
338 }
339
340 if (update)
341 dev->ops.char_update(dev, x, y);
342 }
343 }
344 }
345
346 async_answer_0(iid, EOK);
347}
348
349static void srv_damage(ipc_callid_t iid, ipc_call_t *icall)
350{
351 frontbuf_t *frontbuf = resolve_frontbuf(IPC_GET_ARG1(*icall), iid);
352 if (frontbuf == NULL)
353 return;
354
355 chargrid_t *buf = (chargrid_t *) frontbuf->data;
356
357 list_foreach(outdevs, link, outdev_t, dev) {
358 assert(dev->ops.char_update);
359
360 if (srv_update_scroll(dev, buf))
361 continue;
362
363 sysarg_t col = IPC_GET_ARG2(*icall);
364 sysarg_t row = IPC_GET_ARG3(*icall);
365
366 sysarg_t cols = IPC_GET_ARG4(*icall);
367 sysarg_t rows = IPC_GET_ARG5(*icall);
368
369 for (sysarg_t y = 0; y < rows; y++) {
370 for (sysarg_t x = 0; x < cols; x++) {
371 charfield_t *front_field =
372 chargrid_charfield_at(buf, col + x, row + y);
373 charfield_t *back_field =
374 chargrid_charfield_at(dev->backbuf, col + x, row + y);
375
376 back_field->ch = front_field->ch;
377 back_field->attrs = front_field->attrs;
378 front_field->flags &= ~CHAR_FLAG_DIRTY;
379 dev->ops.char_update(dev, col + x, row + y);
380 }
381 }
382 }
383
384 async_answer_0(iid, EOK);
385}
386
387static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
388{
389 /* Accept the connection */
390 async_answer_0(iid, EOK);
391
392 while (true) {
393 ipc_call_t call;
394 ipc_callid_t callid = async_get_call(&call);
395
396 if (!IPC_GET_IMETHOD(call)) {
397 async_answer_0(callid, EOK);
398 break;
399 }
400
401 switch (IPC_GET_IMETHOD(call)) {
402 case OUTPUT_YIELD:
403 srv_yield(callid, &call);
404 break;
405 case OUTPUT_CLAIM:
406 srv_claim(callid, &call);
407 break;
408 case OUTPUT_GET_DIMENSIONS:
409 srv_get_dimensions(callid, &call);
410 break;
411 case OUTPUT_GET_CAPS:
412 srv_get_caps(callid, &call);
413 break;
414
415 case OUTPUT_FRONTBUF_CREATE:
416 srv_frontbuf_create(callid, &call);
417 break;
418 case OUTPUT_FRONTBUF_DESTROY:
419 srv_frontbuf_destroy(callid, &call);
420 break;
421
422 case OUTPUT_CURSOR_UPDATE:
423 srv_cursor_update(callid, &call);
424 break;
425 case OUTPUT_SET_STYLE:
426 srv_set_style(callid, &call);
427 break;
428 case OUTPUT_SET_COLOR:
429 srv_set_color(callid, &call);
430 break;
431 case OUTPUT_SET_RGB_COLOR:
432 srv_set_rgb_color(callid, &call);
433 break;
434 case OUTPUT_UPDATE:
435 srv_update(callid, &call);
436 break;
437 case OUTPUT_DAMAGE:
438 srv_damage(callid, &call);
439 break;
440
441 default:
442 async_answer_0(callid, EINVAL);
443 }
444 }
445}
446
447static void usage(char *name)
448{
449 printf("Usage: %s <service_name>\n", name);
450}
451
452int main(int argc, char *argv[])
453{
454 if (argc < 2) {
455 usage(argv[0]);
456 return 1;
457 }
458
459 printf("%s: HelenOS output service\n", NAME);
460
461 /* Register server */
462 async_set_fallback_port_handler(client_connection, NULL);
463 int rc = loc_server_register(NAME);
464 if (rc != EOK) {
465 printf("%s: Unable to register driver\n", NAME);
466 return rc;
467 }
468
469 service_id_t service_id;
470 rc = loc_service_register(argv[1], &service_id);
471 if (rc != EOK) {
472 printf("%s: Unable to register service %s\n", NAME, argv[1]);
473 return rc;
474 }
475
476 ega_init();
477 kchar_init();
478 niagara_init();
479 ski_init();
480
481 printf("%s: Accepting connections\n", NAME);
482 task_retval(0);
483 async_manager();
484
485 /* Never reached */
486 return 0;
487}
Note: See TracBrowser for help on using the repository browser.