18e4503279bfcc7797cef7939788b31908a3e440
[platform/upstream/kmscon.git] / src / uvtd_vt.c
1 /*
2  * uvtd - User-space VT daemon
3  *
4  * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files
8  * (the "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26 /*
27  * Virtual Terminals
28  * Every virtual terminal forms a session inside of uvtd. Sessions are scheduled
29  * by the seat/session-scheduler and notified whenever they get active/inactive.
30  */
31
32 #include <errno.h>
33 #include <inttypes.h>
34 #include <linux/kd.h>
35 #include <linux/vt.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <termio.h>
39 #include <termios.h>
40 #include <unistd.h>
41 #include "shl_hook.h"
42 #include "shl_log.h"
43 #include "uvt.h"
44 #include "uvtd_seat.h"
45 #include "uvtd_vt.h"
46
47 #define LOG_SUBSYSTEM "vt"
48
49 struct uvtd_vt {
50         unsigned long ref;
51         struct uvt_ctx *uctx;
52         struct shl_hook *hook;
53         struct uvtd_session *session;
54         bool is_legacy;
55
56         unsigned int mode;
57         unsigned int kbmode;
58 };
59
60 static void vt_hup(struct uvtd_vt *vt)
61 {
62         struct uvt_vt_event ev;
63
64         memset(&ev, 0, sizeof(ev));
65         ev.type = UVT_VT_HUP;
66
67         shl_hook_call(vt->hook, vt, &ev);
68 }
69
70 static int vt_session_event(struct uvtd_session *session, unsigned int event,
71                             void *data)
72 {
73         struct uvtd_vt *vt = data;
74
75         switch (event) {
76         case UVTD_SESSION_UNREGISTER:
77                 vt->session = NULL;
78                 vt_hup(vt);
79                 break;
80         case UVTD_SESSION_ACTIVATE:
81                 log_debug("activate %p", vt);
82                 break;
83         case UVTD_SESSION_DEACTIVATE:
84                 log_debug("deactivate %p", vt);
85                 break;
86         }
87
88         return 0;
89 }
90
91 int uvtd_vt_new(struct uvtd_vt **out, struct uvt_ctx *uctx, unsigned int id,
92                 struct uvtd_seat *seat, bool is_legacy)
93 {
94         struct uvtd_vt *vt;
95         int ret;
96
97         if (!out || !uctx)
98                 return -EINVAL;
99
100         vt = malloc(sizeof(*vt));
101         if (!vt)
102                 return -ENOMEM;
103
104         memset(vt, 0, sizeof(*vt));
105         vt->ref = 1;
106         vt->uctx = uctx;
107         vt->is_legacy = is_legacy;
108         vt->mode = KD_TEXT;
109         vt->kbmode = K_UNICODE;
110
111         ret = shl_hook_new(&vt->hook);
112         if (ret)
113                 goto err_free;
114
115         ret = uvtd_seat_register_session(seat, &vt->session, id,
116                                          vt_session_event, vt);
117         if (ret)
118                 goto err_hook;
119
120         uvt_ctx_ref(vt->uctx);
121         *out = vt;
122         return 0;
123
124 err_hook:
125         shl_hook_free(vt->hook);
126 err_free:
127         free(vt);
128         return ret;
129 }
130
131 void uvtd_vt_ref(struct uvtd_vt *vt)
132 {
133         if (!vt || !vt->ref)
134                 return;
135
136         ++vt->ref;
137 }
138
139 void uvtd_vt_unref(struct uvtd_vt *vt)
140 {
141         if (!vt || !vt->ref || --vt->ref)
142                 return;
143
144         uvtd_session_unregister(vt->session);
145         shl_hook_free(vt->hook);
146         uvt_ctx_unref(vt->uctx);
147         free(vt);
148 }
149
150 int uvtd_vt_register_cb(struct uvtd_vt *vt, uvt_vt_cb cb, void *data)
151 {
152         if (!vt)
153                 return -EINVAL;
154
155         return shl_hook_add_cast(vt->hook, cb, data, false);
156 }
157
158 void uvtd_vt_unregister_cb(struct uvtd_vt *vt, uvt_vt_cb cb, void *data)
159 {
160         if (!vt)
161                 return;
162
163         shl_hook_rm_cast(vt->hook, cb, data);
164 }
165
166 int uvtd_vt_read(struct uvtd_vt *vt, uint8_t *mem, size_t len)
167 {
168         return -EAGAIN;
169 }
170
171 int uvtd_vt_write(struct uvtd_vt *vt, const uint8_t *mem, size_t len)
172 {
173         return len;
174 }
175
176 unsigned int uvtd_vt_poll(struct uvtd_vt *vt)
177 {
178         return UVT_TTY_WRITE;
179 }
180
181 static int vt_ioctl_TCFLSH(void *data, unsigned long arg)
182 {
183         switch (arg) {
184         case TCIFLUSH:
185         case TCOFLUSH:
186         case TCIOFLUSH:
187                 break;
188         default:
189                 return -EINVAL;
190         }
191
192         return 0;
193 }
194
195 static int vt_ioctl_VT_ACTIVATE(void *data, unsigned long arg)
196 {
197         return -EINVAL;
198 }
199
200 static int vt_ioctl_VT_WAITACTIVE(void *data, unsigned long arg)
201 {
202         return -EINVAL;
203 }
204
205 static int vt_ioctl_VT_GETSTATE(void *data, struct vt_stat *arg)
206 {
207         return -EINVAL;
208 }
209
210 static int vt_ioctl_VT_OPENQRY(void *data, unsigned int *arg)
211 {
212         return -EINVAL;
213 }
214
215 static int vt_ioctl_VT_GETMODE(void *data, struct vt_mode *arg)
216 {
217         return -EINVAL;
218 }
219
220 static int vt_ioctl_VT_SETMODE(void *data, const struct vt_mode *arg)
221 {
222         return -EINVAL;
223 }
224
225 static int vt_ioctl_VT_RELDISP(void *data, unsigned long arg)
226 {
227         return -EINVAL;
228 }
229
230 static int vt_ioctl_KDGETMODE(void *data, unsigned int *arg)
231 {
232         struct uvtd_vt *vt = data;
233
234         *arg = vt->mode;
235         return 0;
236 }
237
238 static int vt_ioctl_KDSETMODE(void *data, unsigned int arg)
239 {
240         struct uvtd_vt *vt = data;
241
242         switch (arg) {
243         case KD_TEXT0:
244         case KD_TEXT1:
245                 arg = KD_TEXT;
246                 /* fallthrough */
247         case KD_TEXT:
248         case KD_GRAPHICS:
249                 vt->mode = arg;
250                 break;
251         default:
252                 return -EINVAL;
253         }
254
255         return 0;
256 }
257
258 static int vt_ioctl_KDGKBMODE(void *data, unsigned int *arg)
259 {
260         struct uvtd_vt *vt = data;
261
262         *arg = vt->kbmode;
263         return 0;
264 }
265
266 static int vt_ioctl_KDSKBMODE(void *data, unsigned int arg)
267 {
268         struct uvtd_vt *vt = data;
269
270         switch (arg) {
271         case K_RAW:
272                 /* TODO: what does K_RAW do? */
273         case K_UNICODE:
274         case K_OFF:
275                 vt->kbmode = arg;
276                 break;
277         case K_XLATE:
278         case K_MEDIUMRAW:
279                 /* TODO: do we need these? */
280                 return -EOPNOTSUPP;
281         default:
282                 return -EINVAL;
283         }
284
285         return 0;
286 }
287
288 /* compatibility to UVT-VT ops */
289
290 static void vt_ref(void *vt)
291 {
292         uvtd_vt_ref(vt);
293 }
294
295 static void vt_unref(void *vt)
296 {
297         uvtd_vt_unref(vt);
298 }
299
300 static int vt_register_cb(void *vt, uvt_vt_cb cb, void *data)
301 {
302         return uvtd_vt_register_cb(vt, cb, data);
303 }
304
305 static void vt_unregister_cb(void *vt, uvt_vt_cb cb, void *data)
306 {
307         uvtd_vt_register_cb(vt, cb, data);
308 }
309
310 static int vt_read(void *vt, uint8_t *mem, size_t len)
311 {
312         return uvtd_vt_read(vt, mem, len);
313 }
314
315 static int vt_write(void *vt, const uint8_t *mem, size_t len)
316 {
317         return uvtd_vt_write(vt, mem, len);
318 }
319
320 static unsigned int vt_poll(void *vt)
321 {
322         return uvtd_vt_poll(vt);
323 }
324
325 struct uvt_vt_ops uvtd_vt_ops = {
326         .ref = vt_ref,
327         .unref = vt_unref,
328         .register_cb = vt_register_cb,
329         .unregister_cb = vt_unregister_cb,
330         .read = vt_read,
331         .write = vt_write,
332         .poll = vt_poll,
333
334         .ioctl_TCFLSH = vt_ioctl_TCFLSH,
335
336         .ioctl_VT_ACTIVATE = vt_ioctl_VT_ACTIVATE,
337         .ioctl_VT_WAITACTIVE = vt_ioctl_VT_WAITACTIVE,
338         .ioctl_VT_GETSTATE = vt_ioctl_VT_GETSTATE,
339         .ioctl_VT_OPENQRY = vt_ioctl_VT_OPENQRY,
340         .ioctl_VT_GETMODE = vt_ioctl_VT_GETMODE,
341         .ioctl_VT_SETMODE = vt_ioctl_VT_SETMODE,
342         .ioctl_VT_RELDISP = vt_ioctl_VT_RELDISP,
343         .ioctl_KDGETMODE = vt_ioctl_KDGETMODE,
344         .ioctl_KDSETMODE = vt_ioctl_KDSETMODE,
345         .ioctl_KDGKBMODE = vt_ioctl_KDGKBMODE,
346         .ioctl_KDSKBMODE = vt_ioctl_KDSKBMODE,
347 };