source: mainline/uspace/lib/drv/generic/remote_usbhid.c@ 3679f51a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3679f51a was 3fafe5e0, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix incorrectly indented double-slash comments.

  • Property mode set to 100644
File size: 11.2 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
[3be9d10]285static void remote_usbhid_get_event_length(ddf_fun_t *, void *, cap_call_handle_t, ipc_call_t *);
286static void remote_usbhid_get_event(ddf_fun_t *, void *, cap_call_handle_t, ipc_call_t *);
287static void remote_usbhid_get_report_descriptor_length(ddf_fun_t *, void *, cap_call_handle_t, ipc_call_t *);
288static void remote_usbhid_get_report_descriptor(ddf_fun_t *, void *, cap_call_handle_t, 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,
[a46e56b]308 cap_call_handle_t chandle, 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");
[a46e56b]316 async_answer_0(chandle, ENOTSUP);
[27b85d9]317 return;
318 }
319
[e765ccb]320 size_t len = hid_iface->get_event_length(fun);
[a46e56b]321 async_answer_1(chandle, EOK, len);
[27b85d9]322}
323
324void remote_usbhid_get_event(ddf_fun_t *fun, void *iface,
[a46e56b]325 cap_call_handle_t chandle, ipc_call_t *call)
[27b85d9]326{
327 usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
328
329 if (!hid_iface->get_event) {
[a46e56b]330 async_answer_0(chandle, ENOTSUP);
[27b85d9]331 return;
332 }
333
334 unsigned int flags = DEV_IPC_GET_ARG1(*call);
335
336 size_t len;
[a46e56b]337 cap_call_handle_t data_chandle;
338 if (!async_data_read_receive(&data_chandle, &len)) {
339 async_answer_0(chandle, EPARTY);
[27b85d9]340 return;
341 }
[3fafe5e0]342
[27b85d9]343 if (len == 0) {
[a46e56b]344 async_answer_0(data_chandle, EINVAL);
345 async_answer_0(chandle, EINVAL);
[9dddb3d]346 return;
[27b85d9]347 }
348
[b7fd2a0]349 errno_t rc;
[27b85d9]350
[d7c72db]351 uint8_t *data = malloc(len);
[e765ccb]352 if (data == NULL) {
[a46e56b]353 async_answer_0(data_chandle, ENOMEM);
354 async_answer_0(chandle, ENOMEM);
[9dddb3d]355 return;
[27b85d9]356 }
357
[e765ccb]358 size_t act_length;
[266fcd8]359 int event_nr;
360 rc = hid_iface->get_event(fun, data, len, &act_length, &event_nr, flags);
[27b85d9]361 if (rc != EOK) {
[e765ccb]362 free(data);
[a46e56b]363 async_answer_0(data_chandle, rc);
364 async_answer_0(chandle, 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
[a46e56b]373 async_data_read_finalize(data_chandle, data, act_length);
[27b85d9]374
[e765ccb]375 free(data);
[27b85d9]376
[a46e56b]377 async_answer_1(chandle, EOK, event_nr);
[27b85d9]378}
379
[9dddb3d]380void remote_usbhid_get_report_descriptor_length(ddf_fun_t *fun, void *iface,
[a46e56b]381 cap_call_handle_t chandle, 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) {
[a46e56b]386 async_answer_0(chandle, ENOTSUP);
[9dddb3d]387 return;
388 }
389
390 size_t len = hid_iface->get_report_descriptor_length(fun);
[a46e56b]391 async_answer_1(chandle, EOK, (sysarg_t) len);
[d7c72db]392}
393
[9dddb3d]394void remote_usbhid_get_report_descriptor(ddf_fun_t *fun, void *iface,
[a46e56b]395 cap_call_handle_t chandle, 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) {
[a46e56b]400 async_answer_0(chandle, ENOTSUP);
[9dddb3d]401 return;
402 }
403
404 size_t len;
[a46e56b]405 cap_call_handle_t data_chandle;
406 if (!async_data_read_receive(&data_chandle, &len)) {
407 async_answer_0(chandle, EINVAL);
[9dddb3d]408 return;
409 }
410
411 if (len == 0) {
[a46e56b]412 async_answer_0(data_chandle, EINVAL);
413 async_answer_0(chandle, EINVAL);
[9dddb3d]414 return;
415 }
416
417 uint8_t *descriptor = malloc(len);
418 if (descriptor == NULL) {
[a46e56b]419 async_answer_0(data_chandle, ENOMEM);
420 async_answer_0(chandle, 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);
[a46e56b]432 async_answer_0(data_chandle, rc);
433 async_answer_0(chandle, rc);
[9dddb3d]434 return;
435 }
436
[a46e56b]437 async_data_read_finalize(data_chandle, descriptor, act_len);
438 async_answer_0(chandle, EOK);
[9dddb3d]439
440 free(descriptor);
[d7c72db]441}
442
[9dddb3d]443
444
[27b85d9]445/**
446 * @}
447 */
Note: See TracBrowser for help on using the repository browser.