uvtd: vt: implement VT_GETMODE/SETMODE ioctl state-tracking
[platform/upstream/kmscon.git] / src / uvt_ctx.c
1 /*
2  * UVT - Userspace Virtual Terminals
3  *
4  * Copyright (c) 2011-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  * UVT Contexts
28  * A UVT context is used to provide basic infrastructure for all other UVT
29  * objects. It allows easy integration of multiple UVT objects into a single
30  * application.
31  */
32
33 #include <eloop.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <linux/major.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include "shl_array.h"
41 #include "shl_flagset.h"
42 #include "shl_llog.h"
43 #include "shl_misc.h"
44 #include "uvt.h"
45 #include "uvt_internal.h"
46
47 #define LLOG_SUBSYSTEM "uvt_ctx"
48
49 SHL_EXPORT
50 int uvt_ctx_new(struct uvt_ctx **out, uvt_log_t log, void *log_data)
51 {
52         struct uvt_ctx *ctx;
53         int ret;
54
55         if (!out)
56                 return llog_dEINVAL(log, log_data);
57
58         ctx = malloc(sizeof(*ctx));
59         if (!ctx)
60                 return llog_dENOMEM(log, log_data);
61         memset(ctx, 0, sizeof(*ctx));
62         ctx->ref = 1;
63         ctx->llog = log;
64         ctx->llog_data = log_data;
65
66         /* Default major/minor uses the TTY_MAJOR number with an offset of 2^15
67          * to avoid ID-clashes with any in-kernel TTY driver. As kernel drivers
68          * use static IDs only, a lower number would be fine, too, but lets be
69          * safe and just use high numbers. */
70         ctx->major = TTY_MAJOR;
71         ctx->minor_offset = 16384;
72
73         llog_debug(ctx, "new ctx %p", ctx);
74
75         ret = ev_eloop_new(&ctx->eloop, ctx->llog, ctx->llog_data);
76         if (ret)
77                 goto err_free;
78
79         ctx->cuse_file = strdup("/dev/cuse");
80         if (!ctx->cuse_file) {
81                 ret = llog_ENOMEM(ctx);
82                 goto err_eloop;
83         }
84
85         ret = shl_flagset_new(&ctx->minors);
86         if (ret)
87                 goto err_file;
88
89         *out = ctx;
90         return 0;
91
92 err_file:
93         free(ctx->cuse_file);
94 err_eloop:
95         ev_eloop_unref(ctx->eloop);
96 err_free:
97         free(ctx);
98         return ret;
99 }
100
101 SHL_EXPORT
102 void uvt_ctx_ref(struct uvt_ctx *ctx)
103 {
104         if (!ctx || !ctx->ref)
105                 return;
106
107         ++ctx->ref;
108 }
109
110 SHL_EXPORT
111 void uvt_ctx_unref(struct uvt_ctx *ctx)
112 {
113         if (!ctx || !ctx->ref || --ctx->ref)
114                 return;
115
116         llog_debug(ctx, "free ctx %p", ctx);
117
118         shl_flagset_free(ctx->minors);
119         free(ctx->cuse_file);
120         ev_eloop_unref(ctx->eloop);
121         free(ctx);
122 }
123
124 SHL_EXPORT
125 int uvt_ctx_get_fd(struct uvt_ctx *ctx)
126 {
127         if (!ctx)
128                 return -1;
129
130         return ev_eloop_get_fd(ctx->eloop);
131 }
132
133 SHL_EXPORT
134 void uvt_ctx_dispatch(struct uvt_ctx *ctx)
135 {
136         if (!ctx)
137                 return;
138
139         ev_eloop_dispatch(ctx->eloop, 0);
140 }
141
142 SHL_EXPORT
143 unsigned int uvt_ctx_get_major(struct uvt_ctx *ctx)
144 {
145         return ctx->major;
146 }
147
148 SHL_EXPORT
149 int uvt_ctx_new_minor(struct uvt_ctx *ctx, unsigned int *out)
150 {
151         int ret;
152
153         ret = shl_flagset_alloc(ctx->minors, out);
154         if (ret)
155                 return ret;
156
157         *out += ctx->minor_offset;
158         return 0;
159 }
160
161 SHL_EXPORT
162 void uvt_ctx_free_minor(struct uvt_ctx *ctx, unsigned int minor)
163 {
164         if (!ctx || minor < ctx->minor_offset)
165                 return;
166
167         shl_flagset_unset(ctx->minors, minor - ctx->minor_offset);
168 }