~jsvoboda/helenos/dnsr

« back to all changes in this revision

Viewing changes to uspace/srv/hid/isdv4_tablet/main.c

  • Committer: Jiri Svoboda
  • Date: 2012-11-11 21:31:03 UTC
  • mfrom: (1527.1.178 mainline)
  • Revision ID: jiri@wiwaxia-20121111213103-314bmkettwvlwj97
MergeĀ mainlineĀ changes.

Show diffs side-by-side

added added

removed removed

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