source: mainline/uspace/srv/hid/isdv4_tablet/main.c@ b1834a01

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b1834a01 was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/*
2 * Copyright (c) 2012 Martin Sucha
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 <async.h>
30#include <errno.h>
31#include <fibril_synch.h>
32#include <io/serial.h>
33#include <ipc/mouseev.h>
34#include <loc.h>
35#include <stddef.h>
36#include <stdio.h>
37#include <str.h>
38#include <task.h>
39
40#include "isdv4.h"
41
42#define NAME "isdv4_tablet"
43
44static async_sess_t *client_sess = NULL;
45static fibril_mutex_t client_mutex;
46static isdv4_state_t state;
47
48static void syntax_print(void)
49{
50 fprintf(stderr, "Usage: %s [--baud=<baud>] [--print-events] [device_service]\n", NAME);
51}
52
53static errno_t read_fibril(void *unused)
54{
55 errno_t rc = isdv4_read_events(&state);
56 if (rc != EOK) {
57 fprintf(stderr, "Failed reading events");
58 return rc;
59 }
60
61 isdv4_fini(&state);
62 return EOK;
63}
64
65static void mouse_connection(ipc_call_t *icall, void *arg)
66{
67 async_answer_0(icall, EOK);
68
69 async_sess_t *sess =
70 async_callback_receive(EXCHANGE_SERIALIZE);
71
72 fibril_mutex_lock(&client_mutex);
73
74 if (client_sess == NULL)
75 client_sess = sess;
76
77 fibril_mutex_unlock(&client_mutex);
78
79 while (true) {
80 ipc_call_t call;
81 async_get_call(&call);
82
83 if (!IPC_GET_IMETHOD(call))
84 break;
85
86 async_answer_0(&call, ENOTSUP);
87 }
88}
89
90static void emit_event(const isdv4_event_t *event)
91{
92 fibril_mutex_lock(&client_mutex);
93 async_sess_t *sess = client_sess;
94 fibril_mutex_unlock(&client_mutex);
95
96 if (!sess)
97 return;
98
99 async_exch_t *exch = async_exchange_begin(sess);
100 if (exch) {
101 unsigned int max_x = state.stylus_max_x;
102 unsigned int max_y = state.stylus_max_y;
103 if (event->source == TOUCH) {
104 max_x = state.touch_max_x;
105 max_y = state.touch_max_y;
106 }
107 async_msg_4(exch, MOUSEEV_ABS_MOVE_EVENT, event->x, event->y,
108 max_x, max_y);
109 if (event->type == PRESS || event->type == RELEASE) {
110 async_msg_2(exch, MOUSEEV_BUTTON_EVENT, event->button,
111 event->type == PRESS);
112 }
113 }
114 async_exchange_end(exch);
115}
116
117static void print_and_emit_event(const isdv4_event_t *event)
118{
119 const char *type = NULL;
120 switch (event->type) {
121 case PRESS:
122 type = "PRESS";
123 break;
124 case RELEASE:
125 type = "RELEASE";
126 break;
127 case PROXIMITY_IN:
128 type = "PROXIMITY IN";
129 break;
130 case PROXIMITY_OUT:
131 type = "PROXIMITY OUT";
132 break;
133 case MOVE:
134 type = "MOVE";
135 break;
136 default:
137 type = "UNKNOWN";
138 break;
139 }
140
141 const char *source = NULL;
142 switch (event->source) {
143 case STYLUS_TIP:
144 source = "stylus tip";
145 break;
146 case STYLUS_ERASER:
147 source = "stylus eraser";
148 break;
149 case TOUCH:
150 source = "touch";
151 break;
152 }
153
154 printf("%s %s %u %u %u %u\n", type, source, event->x, event->y,
155 event->pressure, event->button);
156
157 emit_event(event);
158}
159
160static const char *touch_type(unsigned int data_id)
161{
162 switch (data_id) {
163 case 0:
164 return "resistive+stylus";
165 case 1:
166 return "capacitive+stylus";
167 case 2:
168 return "resistive";
169 case 3:
170 case 4:
171 return "capacitive";
172 case 5:
173 return "penabled";
174 }
175 return "unknown";
176}
177
178int main(int argc, char **argv)
179{
180 sysarg_t baud = 38400;
181 service_id_t svc_id;
182 serial_t *serial;
183 char *serial_port_name = NULL;
184
185 int arg = 1;
186 errno_t rc;
187
188 isdv4_event_fn event_fn = emit_event;
189
190 if (argc > arg && str_test_prefix(argv[arg], "--baud=")) {
191 size_t arg_offset = str_lsize(argv[arg], 7);
192 char *arg_str = argv[arg] + arg_offset;
193 if (str_length(arg_str) == 0) {
194 fprintf(stderr, "--baud requires an argument\n");
195 syntax_print();
196 return 1;
197 }
198 char *endptr;
199 baud = strtol(arg_str, &endptr, 10);
200 if (*endptr != '\0') {
201 fprintf(stderr, "Invalid value for baud\n");
202 syntax_print();
203 return 1;
204 }
205 arg++;
206 }
207
208 if (argc > arg && str_cmp(argv[arg], "--print-events") == 0) {
209 event_fn = print_and_emit_event;
210 arg++;
211 }
212
213 if (argc > arg) {
214 serial_port_name = argv[arg];
215 rc = loc_service_get_id(serial_port_name, &svc_id, 0);
216 if (rc != EOK) {
217 fprintf(stderr, "Cannot find device service %s\n",
218 argv[arg]);
219 return 1;
220 }
221 arg++;
222 } else {
223 category_id_t serial_cat_id;
224
225 rc = loc_category_get_id("serial", &serial_cat_id, 0);
226 if (rc != EOK) {
227 fprintf(stderr, "Failed getting id of category "
228 "'serial'\n");
229 return 1;
230 }
231
232 service_id_t *svc_ids;
233 size_t svc_count;
234
235 rc = loc_category_get_svcs(serial_cat_id, &svc_ids, &svc_count);
236 if (rc != EOK) {
237 fprintf(stderr, "Failed getting list of services\n");
238 return 1;
239 }
240
241 if (svc_count == 0) {
242 fprintf(stderr, "No service in category 'serial'\n");
243 free(svc_ids);
244 return 1;
245 }
246
247 svc_id = svc_ids[0];
248
249 rc = loc_service_get_name(svc_id, &serial_port_name);
250 if (rc != EOK) {
251 fprintf(stderr, "Failed getting name of serial service\n");
252 return 1;
253 }
254
255 free(svc_ids);
256 }
257
258 if (argc > arg) {
259 fprintf(stderr, "Too many arguments\n");
260 syntax_print();
261 return 1;
262 }
263
264 fibril_mutex_initialize(&client_mutex);
265
266 printf(NAME ": Using serial port %s\n", serial_port_name);
267
268 async_sess_t *sess = loc_service_connect(svc_id, INTERFACE_DDF,
269 IPC_FLAG_BLOCKING);
270 if (!sess) {
271 fprintf(stderr, "Failed connecting to service\n");
272 return 2;
273 }
274
275 rc = serial_open(sess, &serial);
276 if (rc != EOK) {
277 fprintf(stderr, "Failed opening serial port\n");
278 return 2;
279 }
280
281 rc = serial_set_comm_props(serial, baud, SERIAL_NO_PARITY, 8, 1);
282 if (rc != EOK) {
283 fprintf(stderr, "Failed setting serial properties\n");
284 return 2;
285 }
286
287 rc = isdv4_init(&state, sess, event_fn);
288 if (rc != EOK) {
289 fprintf(stderr, "Failed initializing isdv4 state");
290 return 2;
291 }
292
293 rc = isdv4_init_tablet(&state);
294 if (rc != EOK) {
295 fprintf(stderr, "Failed initializing tablet");
296 return 2;
297 }
298
299 printf("Tablet information:\n");
300 printf(" Stylus: %ux%u pressure: %u tilt: ", state.stylus_max_x,
301 state.stylus_max_y, state.stylus_max_pressure);
302 if (state.stylus_tilt_supported) {
303 printf("%ux%u\n", state.stylus_max_xtilt, state.stylus_max_ytilt);
304 } else {
305 printf("not supported\n");
306 }
307 printf(" Touch: %ux%u type: %s\n", state.touch_max_x, state.touch_max_y,
308 touch_type(state.touch_type));
309
310 fid_t fibril = fibril_create(read_fibril, NULL);
311 /* From this on, state is to be used only by read_fibril */
312 fibril_add_ready(fibril);
313
314 async_set_fallback_port_handler(mouse_connection, NULL);
315 rc = loc_server_register(NAME);
316 if (rc != EOK) {
317 printf("%s: Unable to register driver.\n", NAME);
318 return rc;
319 }
320
321 service_id_t service_id;
322 char *service_name;
323 rc = asprintf(&service_name, "mouse/isdv4-%" PRIun, svc_id);
324 if (rc < 0) {
325 printf(NAME ": Unable to create service name\n");
326 return rc;
327 }
328
329 rc = loc_service_register(service_name, &service_id);
330 if (rc != EOK) {
331 printf(NAME ": Unable to register service %s.\n", service_name);
332 return rc;
333 }
334
335 category_id_t mouse_category;
336 rc = loc_category_get_id("mouse", &mouse_category, IPC_FLAG_BLOCKING);
337 if (rc != EOK) {
338 printf(NAME ": Unable to get mouse category id.\n");
339 } else {
340 rc = loc_service_add_to_cat(service_id, mouse_category);
341 if (rc != EOK) {
342 printf(NAME ": Unable to add device to mouse category.\n");
343 }
344 }
345
346 printf("%s: Accepting connections\n", NAME);
347 task_retval(0);
348 async_manager();
349
350 /* Not reached */
351 return 0;
352}
Note: See TracBrowser for help on using the repository browser.