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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2c7fdaa was 1c635d6, checked in by Martin Sucha <sucha14@…>, 11 years ago

Do not hold a task's return value after it has disconnected.

Holding the task's return value meant that if nobody waited
for task's result, it polluted NS's memory. This was apparently
done because of a race between spawning a task and waiting for it.

We solve this problem in another way: ns discards the return value
as soon as the task disconnects from it. This typically happens
when the task finishes its execution. In order to avoid the race,
we send the wait request to ns while spawning the task (i.e. when
we talk to the loader), but before we allow the loaded program
to run.

Fixes #132

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