source: mainline/uspace/drv/hid/adb-mouse/adb-mouse.c@ 59ff52d

Last change on this file since 59ff52d was 59ff52d, checked in by Jakub Jermar <jakub@…>, 7 years ago

Add async_accept_0() for accepting connections

  • Property mode set to 100644
File size: 5.6 KB
Line 
1/*
2 * Copyright (c) 2011 Martin Decky
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/** @file
30 * @brief ADB mouse driver
31 */
32
33#include <async.h>
34#include <ddf/log.h>
35#include <errno.h>
36#include <ipc/adb.h>
37#include <ipc/mouseev.h>
38#include <loc.h>
39#include <stdio.h>
40
41#include "adb-mouse.h"
42
43static void adb_mouse_conn(ipc_call_t *, void *);
44
45static void adb_mouse_event_button(adb_mouse_t *mouse, int bnum, int bpress)
46{
47 async_exch_t *exch = async_exchange_begin(mouse->client_sess);
48 async_msg_2(exch, MOUSEEV_BUTTON_EVENT, bnum, bpress);
49 async_exchange_end(exch);
50}
51
52static void adb_mouse_event_move(adb_mouse_t *mouse, int dx, int dy, int dz)
53{
54 async_exch_t *exch = async_exchange_begin(mouse->client_sess);
55 async_msg_3(exch, MOUSEEV_MOVE_EVENT, dx, dy, dz);
56 async_exchange_end(exch);
57}
58
59/** Process mouse data */
60static void adb_mouse_data(adb_mouse_t *mouse, sysarg_t data)
61{
62 bool b1, b2;
63 uint16_t udx, udy;
64 int dx, dy;
65
66 /* Extract fields. */
67 b1 = ((data >> 15) & 1) == 0;
68 udy = (data >> 8) & 0x7f;
69 b2 = ((data >> 7) & 1) == 0;
70 udx = data & 0x7f;
71
72 /* Decode 7-bit two's complement signed values. */
73 dx = (udx & 0x40) ? (udx - 0x80) : udx;
74 dy = (udy & 0x40) ? (udy - 0x80) : udy;
75
76 if (b1 != mouse->b1_pressed) {
77 adb_mouse_event_button(mouse, 1, b1);
78 mouse->b1_pressed = b1;
79 }
80
81 if (b2 != mouse->b2_pressed) {
82 adb_mouse_event_button(mouse, 2, b2);
83 mouse->b2_pressed = b2;
84 }
85
86 if (dx != 0 || dy != 0)
87 adb_mouse_event_move(mouse, dx, dy, 0);
88}
89
90static void adb_mouse_events(ipc_call_t *icall, void *arg)
91{
92 adb_mouse_t *mouse = (adb_mouse_t *) arg;
93
94 /* Ignore parameters, the connection is already opened */
95 while (true) {
96 ipc_call_t call;
97 async_get_call(&call);
98
99 errno_t retval = EOK;
100
101 if (!IPC_GET_IMETHOD(call)) {
102 /* TODO: Handle hangup */
103 return;
104 }
105
106 switch (IPC_GET_IMETHOD(call)) {
107 case ADB_REG_NOTIF:
108 adb_mouse_data(mouse, IPC_GET_ARG1(call));
109 break;
110 default:
111 retval = ENOENT;
112 }
113
114 async_answer_0(&call, retval);
115 }
116}
117
118/** Add ADB mouse device */
119errno_t adb_mouse_add(adb_mouse_t *mouse)
120{
121 errno_t rc;
122 bool bound = false;
123
124 mouse->fun = ddf_fun_create(mouse->dev, fun_exposed, "a");
125 if (mouse->fun == NULL) {
126 ddf_msg(LVL_ERROR, "Error creating function");
127 rc = ENOMEM;
128 goto error;
129 }
130
131 mouse->parent_sess = ddf_dev_parent_sess_get(mouse->dev);
132 if (mouse->parent_sess == NULL) {
133 ddf_msg(LVL_ERROR, "Error connecting parent driver");
134 rc = EIO;
135 goto error;
136 }
137
138 async_exch_t *exch = async_exchange_begin(mouse->parent_sess);
139 if (exch == NULL) {
140 ddf_msg(LVL_ERROR, "Error starting exchange with parent");
141 rc = ENOMEM;
142 goto error;
143 }
144
145 port_id_t port;
146 rc = async_create_callback_port(exch, INTERFACE_ADB_CB, 0, 0,
147 adb_mouse_events, mouse, &port);
148
149 async_exchange_end(exch);
150 if (rc != EOK) {
151 ddf_msg(LVL_ERROR, "Error creating callback from device");
152 goto error;
153 }
154
155 ddf_fun_set_conn_handler(mouse->fun, adb_mouse_conn);
156
157 rc = ddf_fun_bind(mouse->fun);
158 if (rc != EOK) {
159 ddf_msg(LVL_ERROR, "Error binding function");
160 goto error;
161 }
162
163 bound = true;
164
165 rc = ddf_fun_add_to_category(mouse->fun, "mouse");
166 if (rc != EOK) {
167 ddf_msg(LVL_ERROR, "Error adding function to category");
168 goto error;
169 }
170
171 return EOK;
172error:
173 if (bound)
174 ddf_fun_unbind(mouse->fun);
175
176 if (mouse->parent_sess != NULL) {
177 async_hangup(mouse->parent_sess);
178 mouse->parent_sess = NULL;
179 }
180
181 if (mouse->fun != NULL) {
182 ddf_fun_destroy(mouse->fun);
183 mouse->fun = NULL;
184 }
185
186 return rc;
187}
188
189/** Remove ADB mouse device */
190errno_t adb_mouse_remove(adb_mouse_t *con)
191{
192 return ENOTSUP;
193}
194
195/** ADB mouse device gone */
196errno_t adb_mouse_gone(adb_mouse_t *con)
197{
198 return ENOTSUP;
199}
200
201/** Handle client connection */
202static void adb_mouse_conn(ipc_call_t *icall, void *arg)
203{
204 ipc_call_t call;
205 sysarg_t method;
206 adb_mouse_t *mouse;
207
208 /*
209 * Answer the first IPC_M_CONNECT_ME_TO call.
210 */
211 async_accept_0(icall);
212
213 mouse = (adb_mouse_t *)ddf_dev_data_get(ddf_fun_get_dev((ddf_fun_t *)arg));
214
215 while (true) {
216 async_get_call(&call);
217 method = IPC_GET_IMETHOD(call);
218
219 if (!method) {
220 /* The other side has hung up. */
221 async_answer_0(&call, EOK);
222 return;
223 }
224
225 async_sess_t *sess =
226 async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
227 if (sess != NULL) {
228 mouse->client_sess = sess;
229 async_answer_0(&call, EOK);
230 } else {
231 async_answer_0(&call, EINVAL);
232 }
233 }
234}
235
236/**
237 * @}
238 */
Note: See TracBrowser for help on using the repository browser.