source: mainline/uspace/srv/hid/display/cfgops.c

Last change on this file was 9546146, checked in by Jiri Svoboda <jiri@…>, 10 months ago

Persistently store display/seat configuration.

  • Property mode set to 100644
File size: 9.9 KB
Line 
1/*
2 * Copyright (c) 2024 Jiri Svoboda
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/** @addtogroup display
30 * @{
31 */
32/**
33 * @file Display configuration ops implementation
34 */
35
36#include <errno.h>
37#include <io/log.h>
38#include <stdlib.h>
39#include <str.h>
40#include <dispcfg_srv.h>
41#include "display.h"
42#include "idevcfg.h"
43#include "main.h"
44#include "seat.h"
45#include "cfgclient.h"
46
47static errno_t dispc_get_seat_list(void *, dispcfg_seat_list_t **);
48static errno_t dispc_get_seat_info(void *, sysarg_t, dispcfg_seat_info_t **);
49static errno_t dispc_seat_create(void *, const char *, sysarg_t *);
50static errno_t dispc_seat_delete(void *, sysarg_t);
51static errno_t dispc_dev_assign(void *, sysarg_t, sysarg_t);
52static errno_t dispc_dev_unassign(void *, sysarg_t);
53static errno_t dispc_get_asgn_dev_list(void *, sysarg_t, dispcfg_dev_list_t **);
54static errno_t dispc_get_event(void *, dispcfg_ev_t *);
55
56dispcfg_ops_t dispcfg_srv_ops = {
57 .get_seat_list = dispc_get_seat_list,
58 .get_seat_info = dispc_get_seat_info,
59 .seat_create = dispc_seat_create,
60 .seat_delete = dispc_seat_delete,
61 .dev_assign = dispc_dev_assign,
62 .dev_unassign = dispc_dev_unassign,
63 .get_asgn_dev_list = dispc_get_asgn_dev_list,
64 .get_event = dispc_get_event,
65};
66
67/** Get seat list.
68 *
69 * @param arg Argument (CFG client)
70 * @param rlist Place to store pointer to new list
71 * @return EOK on success or an error code
72 */
73static errno_t dispc_get_seat_list(void *arg, dispcfg_seat_list_t **rlist)
74{
75 ds_cfgclient_t *cfgclient = (ds_cfgclient_t *)arg;
76 dispcfg_seat_list_t *list;
77 ds_seat_t *seat;
78 unsigned i;
79
80 log_msg(LOG_DEFAULT, LVL_DEBUG, "dispcfg_get_seat_list()");
81
82 list = calloc(1, sizeof(dispcfg_seat_list_t));
83 if (list == NULL)
84 return ENOMEM;
85
86 ds_display_lock(cfgclient->display);
87
88 /* Count the number of seats */
89 list->nseats = 0;
90 seat = ds_display_first_seat(cfgclient->display);
91 while (seat != NULL) {
92 ++list->nseats;
93 seat = ds_display_next_seat(seat);
94 }
95
96 /* Allocate array for seat IDs */
97 list->seats = calloc(list->nseats, sizeof(sysarg_t));
98 if (list->seats == NULL) {
99 ds_display_unlock(cfgclient->display);
100 free(list);
101 return ENOMEM;
102 }
103
104 /* Fill in seat IDs */
105 i = 0;
106 seat = ds_display_first_seat(cfgclient->display);
107 while (seat != NULL) {
108 list->seats[i++] = seat->id;
109 seat = ds_display_next_seat(seat);
110 }
111
112 ds_display_unlock(cfgclient->display);
113 *rlist = list;
114 return EOK;
115}
116
117/** Get seat information.
118 *
119 * @param arg Argument (CFG client)
120 * @param seat_id Seat ID
121 * @param rinfo Place to store pointer to new seat information structure
122 * @return EOK on success or an error code
123 */
124static errno_t dispc_get_seat_info(void *arg, sysarg_t seat_id,
125 dispcfg_seat_info_t **rinfo)
126{
127 ds_cfgclient_t *cfgclient = (ds_cfgclient_t *)arg;
128 ds_seat_t *seat;
129 dispcfg_seat_info_t *info;
130
131 log_msg(LOG_DEFAULT, LVL_DEBUG, "dispcfg_get_seat_info()");
132
133 ds_display_lock(cfgclient->display);
134 seat = ds_display_find_seat(cfgclient->display, seat_id);
135 if (seat == NULL) {
136 ds_display_unlock(cfgclient->display);
137 return ENOENT;
138 }
139
140 info = calloc(1, sizeof(dispcfg_seat_info_t));
141 if (info == NULL) {
142 ds_display_unlock(cfgclient->display);
143 return ENOMEM;
144 }
145
146 (void)seat;
147 info->name = str_dup(seat->name);
148 if (info->name == NULL) {
149 ds_display_unlock(cfgclient->display);
150 free(info);
151 return ENOMEM;
152 }
153
154 ds_display_unlock(cfgclient->display);
155 *rinfo = info;
156 return EOK;
157}
158
159/** Create seat.
160 *
161 * @param arg Argument (CFG client)
162 * @param name Seat name
163 * @param rseat_id Place to store ID of the new seat
164 * @return EOK on success or an error code
165 */
166static errno_t dispc_seat_create(void *arg, const char *name,
167 sysarg_t *rseat_id)
168{
169 ds_cfgclient_t *cfgclient = (ds_cfgclient_t *)arg;
170 ds_seat_t *seat;
171 errno_t rc;
172
173 log_msg(LOG_DEFAULT, LVL_DEBUG, "dispcfg_seat_create()");
174
175 ds_display_lock(cfgclient->display);
176
177 rc = ds_seat_create(cfgclient->display, name, &seat);
178 if (rc != EOK) {
179 ds_display_unlock(cfgclient->display);
180 return rc;
181 }
182
183 (void) ds_display_paint(cfgclient->display, NULL);
184 (void) ds_display_save_cfg(cfgclient->display, cfg_file_path);
185 ds_display_unlock(cfgclient->display);
186
187 *rseat_id = seat->id;
188 return EOK;
189}
190
191/** Delete seat.
192 *
193 * @param arg Argument (CFG client)
194 * @param seat_id Seat ID
195 * @return EOK on success or an error code
196 */
197static errno_t dispc_seat_delete(void *arg, sysarg_t seat_id)
198{
199 ds_cfgclient_t *cfgclient = (ds_cfgclient_t *)arg;
200 ds_seat_t *seat;
201 ds_seat_t *s;
202
203 log_msg(LOG_DEFAULT, LVL_DEBUG, "dispcfg_seat_delete()");
204
205 ds_display_lock(cfgclient->display);
206 seat = ds_display_find_seat(cfgclient->display, seat_id);
207 if (seat == NULL) {
208 ds_display_unlock(cfgclient->display);
209 return ENOENT;
210 }
211
212 /* Verify we are not deleting the last seat */
213 s = ds_display_first_seat(cfgclient->display);
214 if (s == seat && ds_display_next_seat(s) == NULL) {
215 ds_display_unlock(cfgclient->display);
216 return EBUSY;
217 }
218
219 ds_seat_destroy(seat);
220
221 (void) ds_display_paint(cfgclient->display, NULL);
222 (void) ds_display_save_cfg(cfgclient->display, cfg_file_path);
223 ds_display_unlock(cfgclient->display);
224
225 return EOK;
226}
227
228/** Assign device to seat.
229 *
230 * @param arg Argument (CFG client)
231 * @param svc_id Device service ID
232 * @param seat_id Seat ID
233 * @return EOK on success or an error code
234 */
235static errno_t dispc_dev_assign(void *arg, sysarg_t svc_id, sysarg_t seat_id)
236{
237 ds_cfgclient_t *cfgclient = (ds_cfgclient_t *)arg;
238 ds_seat_t *seat;
239 ds_idevcfg_t *idevcfg;
240 errno_t rc;
241
242 log_msg(LOG_DEFAULT, LVL_DEBUG, "dispcfg_dev_assign()");
243
244 ds_display_lock(cfgclient->display);
245 seat = ds_display_find_seat(cfgclient->display, seat_id);
246 if (seat == NULL) {
247 ds_display_unlock(cfgclient->display);
248 return ENOENT;
249 }
250
251 rc = ds_idevcfg_create(cfgclient->display, svc_id, seat, &idevcfg);
252 if (rc != EOK) {
253 assert(rc == ENOMEM);
254 ds_display_unlock(cfgclient->display);
255 return ENOMEM;
256 }
257
258 (void)idevcfg;
259
260 (void) ds_display_save_cfg(cfgclient->display, cfg_file_path);
261 ds_display_unlock(cfgclient->display);
262 return EOK;
263}
264
265/** Unassign device from any seat.
266 *
267 * @param arg Argument (CFG client)
268 * @param svc_id Device service ID
269 * @return EOK on success or an error code
270 */
271static errno_t dispc_dev_unassign(void *arg, sysarg_t svc_id)
272{
273 ds_cfgclient_t *cfgclient = (ds_cfgclient_t *)arg;
274 ds_idevcfg_t *idevcfg;
275
276 log_msg(LOG_DEFAULT, LVL_DEBUG, "dispcfg_dev_unassign()");
277
278 ds_display_lock(cfgclient->display);
279
280 idevcfg = ds_display_first_idevcfg(cfgclient->display);
281 while (idevcfg != NULL) {
282 if (idevcfg->svc_id == svc_id)
283 break;
284
285 idevcfg = ds_display_next_idevcfg(idevcfg);
286 }
287
288 if (idevcfg == NULL) {
289 ds_display_unlock(cfgclient->display);
290 return ENOENT;
291 }
292
293 ds_idevcfg_destroy(idevcfg);
294 (void) ds_display_save_cfg(cfgclient->display, cfg_file_path);
295 ds_display_unlock(cfgclient->display);
296 return EOK;
297}
298
299/** Get assigned device list.
300 *
301 * @param arg Argument (CFG client)
302 * @param seat_id Seat ID
303 * @param rlist Place to store pointer to new list
304 * @return EOK on success or an error code
305 */
306static errno_t dispc_get_asgn_dev_list(void *arg, sysarg_t seat_id,
307 dispcfg_dev_list_t **rlist)
308{
309 ds_cfgclient_t *cfgclient = (ds_cfgclient_t *)arg;
310 dispcfg_dev_list_t *list;
311 ds_seat_t *seat;
312 ds_idevcfg_t *idevcfg;
313 unsigned i;
314
315 log_msg(LOG_DEFAULT, LVL_DEBUG, "dispcfg_get_asgn_dev_list()");
316
317 list = calloc(1, sizeof(dispcfg_dev_list_t));
318 if (list == NULL)
319 return ENOMEM;
320
321 ds_display_lock(cfgclient->display);
322
323 seat = ds_display_find_seat(cfgclient->display, seat_id);
324 if (seat == NULL) {
325 ds_display_unlock(cfgclient->display);
326 free(list);
327 return ENOENT;
328 }
329
330 /* Count the number of devices */
331 list->ndevs = 0;
332 idevcfg = ds_seat_first_idevcfg(seat);
333 while (idevcfg != NULL) {
334 ++list->ndevs;
335 idevcfg = ds_display_next_idevcfg(idevcfg);
336 }
337
338 /* Allocate array for device IDs */
339 list->devs = calloc(list->ndevs, sizeof(sysarg_t));
340 if (list->devs == NULL) {
341 ds_display_unlock(cfgclient->display);
342 free(list);
343 return ENOMEM;
344 }
345
346 /* Fill in device IDs */
347 i = 0;
348 idevcfg = ds_seat_first_idevcfg(seat);
349 while (idevcfg != NULL) {
350 list->devs[i++] = idevcfg->svc_id;
351 idevcfg = ds_display_next_idevcfg(idevcfg);
352 }
353
354 ds_display_unlock(cfgclient->display);
355 *rlist = list;
356 return EOK;
357}
358
359/** Get display configuration event.
360 *
361 * @param arg Argument (CFG client)
362 * @param ev Place to store event
363 * @return EOK on success, ENOENT if there are no events
364 */
365static errno_t dispc_get_event(void *arg, dispcfg_ev_t *ev)
366{
367 ds_cfgclient_t *cfgclient = (ds_cfgclient_t *)arg;
368 errno_t rc;
369
370 log_msg(LOG_DEFAULT, LVL_DEBUG, "dispcfg_get_event()");
371
372 ds_display_lock(cfgclient->display);
373 rc = ds_cfgclient_get_event(cfgclient, ev);
374 ds_display_unlock(cfgclient->display);
375 return rc;
376}
377
378/** @}
379 */
Note: See TracBrowser for help on using the repository browser.