source: mainline/uspace/drv/hid/adb-kbd/adb-kbd.c@ 43ba118

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 43ba118 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: 5.2 KB
Line 
1/*
2 * Copyright (c) 2011 Jiri Svoboda
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 keyboard port driver.
31 */
32
33#include <async.h>
34#include <ddf/log.h>
35#include <errno.h>
36#include <io/console.h>
37#include <ipc/adb.h>
38#include <ipc/kbdev.h>
39#include <loc.h>
40#include <vfs/vfs.h>
41
42#include "adb-kbd.h"
43#include "ctl.h"
44
45static void adb_kbd_events(ipc_call_t *, void *);
46static void adb_kbd_reg0_data(adb_kbd_t *, uint16_t);
47static void adb_kbd_conn(ipc_call_t *, void *);
48
49/** Add ADB keyboard device */
50errno_t adb_kbd_add(adb_kbd_t *kbd)
51{
52 errno_t rc;
53 bool bound = false;
54
55 kbd->fun = ddf_fun_create(kbd->dev, fun_exposed, "a");
56 if (kbd->fun == NULL) {
57 ddf_msg(LVL_ERROR, "Error creating function");
58 rc = ENOMEM;
59 goto error;
60 }
61
62 kbd->parent_sess = ddf_dev_parent_sess_get(kbd->dev);
63 if (kbd->parent_sess == NULL) {
64 ddf_msg(LVL_ERROR, "Error connecting parent driver");
65 rc = EIO;
66 goto error;
67 }
68
69 async_exch_t *exch = async_exchange_begin(kbd->parent_sess);
70 if (exch == NULL) {
71 ddf_msg(LVL_ERROR, "Error starting exchange with parent");
72 rc = ENOMEM;
73 goto error;
74 }
75
76 port_id_t port;
77 rc = async_create_callback_port(exch, INTERFACE_ADB_CB, 0, 0,
78 adb_kbd_events, kbd, &port);
79
80 async_exchange_end(exch);
81 if (rc != EOK) {
82 ddf_msg(LVL_ERROR, "Error creating callback from device");
83 goto error;
84 }
85
86 ddf_fun_set_conn_handler(kbd->fun, adb_kbd_conn);
87
88 rc = ddf_fun_bind(kbd->fun);
89 if (rc != EOK) {
90 ddf_msg(LVL_ERROR, "Error binding function");
91 goto error;
92 }
93
94 bound = true;
95
96 rc = ddf_fun_add_to_category(kbd->fun, "keyboard");
97 if (rc != EOK) {
98 ddf_msg(LVL_ERROR, "Error adding function to category");
99 goto error;
100 }
101
102 return EOK;
103error:
104 if (bound)
105 ddf_fun_unbind(kbd->fun);
106
107 if (kbd->parent_sess != NULL) {
108 async_hangup(kbd->parent_sess);
109 kbd->parent_sess = NULL;
110 }
111
112 if (kbd->fun != NULL) {
113 ddf_fun_destroy(kbd->fun);
114 kbd->fun = NULL;
115 }
116
117 return rc;
118}
119
120/** Remove ADB keyboard device */
121errno_t adb_kbd_remove(adb_kbd_t *con)
122{
123 return ENOTSUP;
124}
125
126/** ADB keyboard device gone */
127errno_t adb_kbd_gone(adb_kbd_t *con)
128{
129 return ENOTSUP;
130}
131
132static void adb_kbd_events(ipc_call_t *icall, void *arg)
133{
134 adb_kbd_t *kbd = (adb_kbd_t *) arg;
135
136 /* Ignore parameters, the connection is already opened */
137 while (true) {
138 ipc_call_t call;
139 async_get_call(&call);
140
141 errno_t retval = EOK;
142
143 if (!IPC_GET_IMETHOD(call)) {
144 /* TODO: Handle hangup */
145 return;
146 }
147
148 switch (IPC_GET_IMETHOD(call)) {
149 case ADB_REG_NOTIF:
150 adb_kbd_reg0_data(kbd, IPC_GET_ARG1(call));
151 break;
152 default:
153 retval = ENOENT;
154 }
155 async_answer_0(&call, retval);
156 }
157}
158
159static void adb_kbd_data(adb_kbd_t *kbd, uint8_t b)
160{
161 kbd_event_type_t etype;
162 unsigned int key;
163 errno_t rc;
164
165 rc = adb_kbd_key_translate(b, &etype, &key);
166 if (rc != EOK)
167 return;
168
169 if (kbd->client_sess == NULL)
170 return;
171
172 async_exch_t *exch = async_exchange_begin(kbd->client_sess);
173 async_msg_4(exch, KBDEV_EVENT, etype, key, 0, 0);
174 async_exchange_end(exch);
175}
176
177static void adb_kbd_reg0_data(adb_kbd_t *kbd, uint16_t data)
178{
179 uint8_t b0 = (data >> 8) & 0xff;
180 uint8_t b1 = data & 0xff;
181
182 if (b0 != 0xff)
183 adb_kbd_data(kbd, b0);
184
185 if (b1 != 0xff)
186 adb_kbd_data(kbd, b1);
187 (void)b0;
188 (void)b1;
189}
190
191/** Handle client connection */
192static void adb_kbd_conn(ipc_call_t *icall, void *arg)
193{
194 ipc_call_t call;
195 sysarg_t method;
196 adb_kbd_t *kbd;
197
198 /*
199 * Answer the first IPC_M_CONNECT_ME_TO call.
200 */
201 async_answer_0(icall, EOK);
202
203 kbd = (adb_kbd_t *)ddf_dev_data_get(ddf_fun_get_dev((ddf_fun_t *)arg));
204
205 while (true) {
206 async_get_call(&call);
207 method = IPC_GET_IMETHOD(call);
208
209 if (!method) {
210 /* The other side has hung up. */
211 async_answer_0(&call, EOK);
212 return;
213 }
214
215 async_sess_t *sess =
216 async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
217 if (sess != NULL) {
218 kbd->client_sess = sess;
219 async_answer_0(&call, EOK);
220 } else {
221 async_answer_0(&call, EINVAL);
222 }
223 }
224}
225
226/**
227 * @}
228 */
Note: See TracBrowser for help on using the repository browser.