source: mainline/uspace/lib/drv/generic/remote_usbhid.c@ 47203ee3

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 47203ee3 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: 10.9 KB
RevLine 
[27b85d9]1/*
2 * Copyright (c) 2010-2011 Vojtech Horky
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/** @addtogroup libdrv
30 * @{
31 */
32/** @file
33 */
34
35#include <async.h>
36#include <errno.h>
37#include <assert.h>
[4e78236]38#include <stdio.h>
[9be30cdf]39#include <macros.h>
[27b85d9]40
41#include "usbhid_iface.h"
42#include "ddf/driver.h"
43
[a44424f]44/** IPC methods for USB HID device interface. */
45typedef enum {
46 /** Get number of events reported in single burst.
47 * Parameters: none
48 * Answer:
49 * - Size of one report in bytes.
50 */
51 IPC_M_USBHID_GET_EVENT_LENGTH,
52 /** Get single event from the HID device.
53 * The word single refers to set of individual events that were
54 * available at particular point in time.
55 * Parameters:
56 * - flags
57 * The call is followed by data read expecting two concatenated
58 * arrays.
59 * Answer:
60 * - EOK - events returned
61 * - EAGAIN - no event ready (only in non-blocking mode)
62 *
63 * It is okay if the client requests less data. Extra data must
64 * be truncated by the driver.
65 *
66 * @todo Change this comment.
67 */
68 IPC_M_USBHID_GET_EVENT,
[a35b458]69
[a44424f]70 /** Get the size of the report descriptor from the HID device.
71 *
72 * Parameters:
73 * - none
74 * Answer:
75 * - EOK - method is implemented (expected always)
76 * Parameters of the answer:
77 * - Size of the report in bytes.
78 */
79 IPC_M_USBHID_GET_REPORT_DESCRIPTOR_LENGTH,
[a35b458]80
[a44424f]81 /** Get the report descriptor from the HID device.
82 *
83 * Parameters:
84 * - none
85 * The call is followed by data read expecting the descriptor itself.
86 * Answer:
87 * - EOK - report descriptor returned.
88 */
89 IPC_M_USBHID_GET_REPORT_DESCRIPTOR
90} usbhid_iface_funcs_t;
91
92/** Ask for event array length.
93 *
94 * @param dev_sess Session to DDF device providing USB HID interface.
95 *
[cde999a]96 * @return Number of usages returned or an error code.
[a44424f]97 *
98 */
[b7fd2a0]99errno_t usbhid_dev_get_event_length(async_sess_t *dev_sess, size_t *size)
[a44424f]100{
101 if (!dev_sess)
102 return EINVAL;
[a35b458]103
[a44424f]104 async_exch_t *exch = async_exchange_begin(dev_sess);
[a35b458]105
[a44424f]106 sysarg_t len;
[b7fd2a0]107 errno_t rc = async_req_1_1(exch, DEV_IFACE_ID(USBHID_DEV_IFACE),
[a44424f]108 IPC_M_USBHID_GET_EVENT_LENGTH, &len);
[a35b458]109
[a44424f]110 async_exchange_end(exch);
[a35b458]111
[a44424f]112 if (rc == EOK) {
113 if (size != NULL)
114 *size = (size_t) len;
115 }
[a35b458]116
[a44424f]117 return rc;
118}
119
120/** Request for next event from HID device.
121 *
122 * @param[in] dev_sess Session to DDF device providing USB HID interface.
123 * @param[out] usage_pages Where to store usage pages.
124 * @param[out] usages Where to store usages (actual data).
125 * @param[in] usage_count Length of @p usage_pages and @p usages buffer
126 * (in items, not bytes).
127 * @param[out] actual_usage_count Number of usages actually returned by the
128 * device driver.
129 * @param[in] flags Flags (see USBHID_IFACE_FLAG_*).
130 *
131 * @return Error code.
132 *
133 */
[b7fd2a0]134errno_t usbhid_dev_get_event(async_sess_t *dev_sess, uint8_t *buf,
[a44424f]135 size_t size, size_t *actual_size, int *event_nr, unsigned int flags)
136{
137 if (!dev_sess)
138 return EINVAL;
[a35b458]139
[a44424f]140 if (buf == NULL)
141 return ENOMEM;
[a35b458]142
[a44424f]143 if (size == 0)
144 return EINVAL;
[a35b458]145
[a44424f]146 size_t buffer_size = size;
147 uint8_t *buffer = malloc(buffer_size);
148 if (buffer == NULL)
149 return ENOMEM;
[a35b458]150
[a44424f]151 async_exch_t *exch = async_exchange_begin(dev_sess);
[a35b458]152
[a44424f]153 ipc_call_t opening_request_call;
154 aid_t opening_request = async_send_2(exch,
155 DEV_IFACE_ID(USBHID_DEV_IFACE), IPC_M_USBHID_GET_EVENT,
156 flags, &opening_request_call);
[a35b458]157
[a44424f]158 if (opening_request == 0) {
159 async_exchange_end(exch);
160 free(buffer);
161 return ENOMEM;
162 }
[a35b458]163
[a44424f]164 ipc_call_t data_request_call;
165 aid_t data_request = async_data_read(exch, buffer, buffer_size,
166 &data_request_call);
[a35b458]167
[a44424f]168 async_exchange_end(exch);
[a35b458]169
[a44424f]170 if (data_request == 0) {
171 async_forget(opening_request);
172 free(buffer);
173 return ENOMEM;
174 }
[a35b458]175
[b7fd2a0]176 errno_t data_request_rc;
177 errno_t opening_request_rc;
[a44424f]178 async_wait_for(data_request, &data_request_rc);
179 async_wait_for(opening_request, &opening_request_rc);
[a35b458]180
[a44424f]181 if (data_request_rc != EOK) {
182 /* Prefer return code of the opening request. */
183 if (opening_request_rc != EOK)
[b7fd2a0]184 return (errno_t) opening_request_rc;
[a44424f]185 else
[b7fd2a0]186 return (errno_t) data_request_rc;
[a44424f]187 }
[a35b458]188
[a44424f]189 if (opening_request_rc != EOK)
[b7fd2a0]190 return (errno_t) opening_request_rc;
[a35b458]191
[a44424f]192 size_t act_size = IPC_GET_ARG2(data_request_call);
[a35b458]193
[a44424f]194 /* Copy the individual items. */
195 memcpy(buf, buffer, act_size);
[a35b458]196
[a44424f]197 if (actual_size != NULL)
198 *actual_size = act_size;
[a35b458]199
[a44424f]200 if (event_nr != NULL)
201 *event_nr = IPC_GET_ARG1(opening_request_call);
[a35b458]202
[a44424f]203 return EOK;
204}
205
[b7fd2a0]206errno_t usbhid_dev_get_report_descriptor_length(async_sess_t *dev_sess,
[a44424f]207 size_t *size)
208{
209 if (!dev_sess)
210 return EINVAL;
[a35b458]211
[a44424f]212 async_exch_t *exch = async_exchange_begin(dev_sess);
[a35b458]213
[a44424f]214 sysarg_t arg_size;
[b7fd2a0]215 errno_t rc = async_req_1_1(exch, DEV_IFACE_ID(USBHID_DEV_IFACE),
[a44424f]216 IPC_M_USBHID_GET_REPORT_DESCRIPTOR_LENGTH, &arg_size);
[a35b458]217
[a44424f]218 async_exchange_end(exch);
[a35b458]219
[a44424f]220 if (rc == EOK) {
221 if (size != NULL)
222 *size = (size_t) arg_size;
223 }
[a35b458]224
[a44424f]225 return rc;
226}
227
[b7fd2a0]228errno_t usbhid_dev_get_report_descriptor(async_sess_t *dev_sess, uint8_t *buf,
[a44424f]229 size_t size, size_t *actual_size)
230{
231 if (!dev_sess)
232 return EINVAL;
[a35b458]233
[a44424f]234 if (buf == NULL)
235 return ENOMEM;
[a35b458]236
[a44424f]237 if (size == 0)
238 return EINVAL;
[a35b458]239
[a44424f]240 async_exch_t *exch = async_exchange_begin(dev_sess);
[a35b458]241
[a44424f]242 aid_t opening_request = async_send_1(exch,
243 DEV_IFACE_ID(USBHID_DEV_IFACE), IPC_M_USBHID_GET_REPORT_DESCRIPTOR,
244 NULL);
245 if (opening_request == 0) {
246 async_exchange_end(exch);
247 return ENOMEM;
248 }
[a35b458]249
[a44424f]250 ipc_call_t data_request_call;
251 aid_t data_request = async_data_read(exch, buf, size,
252 &data_request_call);
[a35b458]253
[a44424f]254 async_exchange_end(exch);
[a35b458]255
[a44424f]256 if (data_request == 0) {
257 async_forget(opening_request);
258 return ENOMEM;
259 }
[a35b458]260
[b7fd2a0]261 errno_t data_request_rc;
262 errno_t opening_request_rc;
[a44424f]263 async_wait_for(data_request, &data_request_rc);
264 async_wait_for(opening_request, &opening_request_rc);
[a35b458]265
[a44424f]266 if (data_request_rc != EOK) {
267 /* Prefer return code of the opening request. */
268 if (opening_request_rc != EOK)
[b7fd2a0]269 return (errno_t) opening_request_rc;
[a44424f]270 else
[b7fd2a0]271 return (errno_t) data_request_rc;
[a44424f]272 }
[a35b458]273
[a44424f]274 if (opening_request_rc != EOK)
[b7fd2a0]275 return (errno_t) opening_request_rc;
[a35b458]276
[a44424f]277 size_t act_size = IPC_GET_ARG2(data_request_call);
[a35b458]278
[a44424f]279 if (actual_size != NULL)
280 *actual_size = act_size;
[a35b458]281
[a44424f]282 return EOK;
283}
284
[984a9ba]285static void remote_usbhid_get_event_length(ddf_fun_t *, void *, ipc_call_t *);
286static void remote_usbhid_get_event(ddf_fun_t *, void *, ipc_call_t *);
287static void remote_usbhid_get_report_descriptor_length(ddf_fun_t *, void *, ipc_call_t *);
288static void remote_usbhid_get_report_descriptor(ddf_fun_t *, void *, ipc_call_t *);
[27b85d9]289
290/** Remote USB HID interface operations. */
[9be30cdf]291static const remote_iface_func_ptr_t remote_usbhid_iface_ops [] = {
[f9d9184]292 [IPC_M_USBHID_GET_EVENT_LENGTH] = remote_usbhid_get_event_length,
293 [IPC_M_USBHID_GET_EVENT] = remote_usbhid_get_event,
294 [IPC_M_USBHID_GET_REPORT_DESCRIPTOR_LENGTH] =
295 remote_usbhid_get_report_descriptor_length,
296 [IPC_M_USBHID_GET_REPORT_DESCRIPTOR] = remote_usbhid_get_report_descriptor
[27b85d9]297};
298
299/** Remote USB HID interface structure.
300 */
[7f80313]301const remote_iface_t remote_usbhid_iface = {
[9be30cdf]302 .method_count = ARRAY_SIZE(remote_usbhid_iface_ops),
[27b85d9]303 .methods = remote_usbhid_iface_ops
304};
305
306
307void remote_usbhid_get_event_length(ddf_fun_t *fun, void *iface,
[984a9ba]308 ipc_call_t *call)
[27b85d9]309{
[e7079cf]310 printf("remote_usbhid_get_event_length()\n");
[a35b458]311
[27b85d9]312 usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
313
314 if (!hid_iface->get_event_length) {
[e7079cf]315 printf("Get event length not set!\n");
[984a9ba]316 async_answer_0(call, ENOTSUP);
[27b85d9]317 return;
318 }
319
[e765ccb]320 size_t len = hid_iface->get_event_length(fun);
[984a9ba]321 async_answer_1(call, EOK, len);
[27b85d9]322}
323
324void remote_usbhid_get_event(ddf_fun_t *fun, void *iface,
[984a9ba]325 ipc_call_t *call)
[27b85d9]326{
327 usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
328
329 if (!hid_iface->get_event) {
[984a9ba]330 async_answer_0(call, ENOTSUP);
[27b85d9]331 return;
332 }
333
334 unsigned int flags = DEV_IPC_GET_ARG1(*call);
335
[984a9ba]336 ipc_call_t data;
[27b85d9]337 size_t len;
[984a9ba]338 if (!async_data_read_receive(&data, &len)) {
339 async_answer_0(call, EPARTY);
[27b85d9]340 return;
341 }
[3fafe5e0]342
[27b85d9]343 if (len == 0) {
[984a9ba]344 async_answer_0(&data, EINVAL);
345 async_answer_0(call, EINVAL);
[9dddb3d]346 return;
[27b85d9]347 }
348
[b7fd2a0]349 errno_t rc;
[27b85d9]350
[984a9ba]351 uint8_t *event = malloc(len);
352 if (event == NULL) {
353 async_answer_0(&data, ENOMEM);
354 async_answer_0(call, ENOMEM);
[9dddb3d]355 return;
[27b85d9]356 }
357
[e765ccb]358 size_t act_length;
[266fcd8]359 int event_nr;
[984a9ba]360 rc = hid_iface->get_event(fun, event, len, &act_length, &event_nr, flags);
[27b85d9]361 if (rc != EOK) {
[984a9ba]362 free(event);
363 async_answer_0(&data, rc);
364 async_answer_0(call, rc);
[9dddb3d]365 return;
[27b85d9]366 }
[e765ccb]367 if (act_length >= len) {
[27b85d9]368 /* This shall not happen. */
369 // FIXME: how about an assert here?
[e765ccb]370 act_length = len;
[27b85d9]371 }
372
[984a9ba]373 async_data_read_finalize(&data, event, act_length);
[27b85d9]374
[984a9ba]375 free(event);
[27b85d9]376
[984a9ba]377 async_answer_1(call, EOK, event_nr);
[27b85d9]378}
379
[9dddb3d]380void remote_usbhid_get_report_descriptor_length(ddf_fun_t *fun, void *iface,
[984a9ba]381 ipc_call_t *call)
[d7c72db]382{
[9dddb3d]383 usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
384
385 if (!hid_iface->get_report_descriptor_length) {
[984a9ba]386 async_answer_0(call, ENOTSUP);
[9dddb3d]387 return;
388 }
389
390 size_t len = hid_iface->get_report_descriptor_length(fun);
[984a9ba]391 async_answer_1(call, EOK, (sysarg_t) len);
[d7c72db]392}
393
[9dddb3d]394void remote_usbhid_get_report_descriptor(ddf_fun_t *fun, void *iface,
[984a9ba]395 ipc_call_t *call)
[d7c72db]396{
[9dddb3d]397 usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
398
399 if (!hid_iface->get_report_descriptor) {
[984a9ba]400 async_answer_0(call, ENOTSUP);
[9dddb3d]401 return;
402 }
403
[984a9ba]404 ipc_call_t data;
[9dddb3d]405 size_t len;
[984a9ba]406 if (!async_data_read_receive(&data, &len)) {
407 async_answer_0(call, EINVAL);
[9dddb3d]408 return;
409 }
410
411 if (len == 0) {
[984a9ba]412 async_answer_0(&data, EINVAL);
413 async_answer_0(call, EINVAL);
[9dddb3d]414 return;
415 }
416
417 uint8_t *descriptor = malloc(len);
418 if (descriptor == NULL) {
[984a9ba]419 async_answer_0(&data, ENOMEM);
420 async_answer_0(call, ENOMEM);
[9dddb3d]421 return;
422 }
423
424 size_t act_len = 0;
[b7fd2a0]425 errno_t rc = hid_iface->get_report_descriptor(fun, descriptor, len,
[9dddb3d]426 &act_len);
427 if (act_len > len) {
428 rc = ELIMIT;
429 }
430 if (rc != EOK) {
431 free(descriptor);
[984a9ba]432 async_answer_0(&data, rc);
433 async_answer_0(call, rc);
[9dddb3d]434 return;
435 }
436
[984a9ba]437 async_data_read_finalize(&data, descriptor, act_len);
438 async_answer_0(call, EOK);
[9dddb3d]439
440 free(descriptor);
[d7c72db]441}
442
[27b85d9]443/**
444 * @}
445 */
Note: See TracBrowser for help on using the repository browser.