source: mainline/uspace/srv/hid/output/output.c@ 870f78c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 870f78c was feeac0d, checked in by Jiri Svoboda <jiri@…>, 12 years ago

Simplify use of list_foreach.

  • 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
435 case OUTPUT_UPDATE:
436 srv_update(callid, &call);
437 break;
438 case OUTPUT_DAMAGE:
439 srv_damage(callid, &call);
440 break;
441
442 default:
443 async_answer_0(callid, EINVAL);
444 }
445 }
446}
447
448static void usage(char *name)
449{
450 printf("Usage: %s <service_name>\n", name);
451}
452
453int main(int argc, char *argv[])
454{
455 if (argc < 2) {
456 usage(argv[0]);
457 return 1;
458 }
459
460 printf("%s: HelenOS output service\n", NAME);
461
462 /* Register server */
463 async_set_client_connection(client_connection);
464 int rc = loc_server_register(NAME);
465 if (rc != EOK) {
466 printf("%s: Unable to register driver\n", NAME);
467 return rc;
468 }
469
470 service_id_t service_id;
471 rc = loc_service_register(argv[1], &service_id);
472 if (rc != EOK) {
473 printf("%s: Unable to register service %s\n", NAME, argv[1]);
474 return rc;
475 }
476
477 ega_init();
478 kchar_init();
479 niagara_init();
480 ski_init();
481
482 printf("%s: Accepting connections\n", NAME);
483 task_retval(0);
484 async_manager();
485
486 /* Never reached */
487 return 0;
488}
Note: See TracBrowser for help on using the repository browser.