source: mainline/uspace/srv/hid/output/output.c@ 42d08592

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 42d08592 was 2f6ad06, checked in by Jakub Jermar <jakub@…>, 9 years ago

Include task.h

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