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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b9076db 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
Line 
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>
38#include <stdio.h>
39#include <macros.h>
40
41#include "usbhid_iface.h"
42#include "ddf/driver.h"
43
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,
69
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,
80
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 *
96 * @return Number of usages returned or an error code.
97 *
98 */
99errno_t usbhid_dev_get_event_length(async_sess_t *dev_sess, size_t *size)
100{
101 if (!dev_sess)
102 return EINVAL;
103
104 async_exch_t *exch = async_exchange_begin(dev_sess);
105
106 sysarg_t len;
107 errno_t rc = async_req_1_1(exch, DEV_IFACE_ID(USBHID_DEV_IFACE),
108 IPC_M_USBHID_GET_EVENT_LENGTH, &len);
109
110 async_exchange_end(exch);
111
112 if (rc == EOK) {
113 if (size != NULL)
114 *size = (size_t) len;
115 }
116
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 */
134errno_t usbhid_dev_get_event(async_sess_t *dev_sess, uint8_t *buf,
135 size_t size, size_t *actual_size, int *event_nr, unsigned int flags)
136{
137 if (!dev_sess)
138 return EINVAL;
139
140 if (buf == NULL)
141 return ENOMEM;
142
143 if (size == 0)
144 return EINVAL;
145
146 size_t buffer_size = size;
147 uint8_t *buffer = malloc(buffer_size);
148 if (buffer == NULL)
149 return ENOMEM;
150
151 async_exch_t *exch = async_exchange_begin(dev_sess);
152
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);
157
158 if (opening_request == 0) {
159 async_exchange_end(exch);
160 free(buffer);
161 return ENOMEM;
162 }
163
164 ipc_call_t data_request_call;
165 aid_t data_request = async_data_read(exch, buffer, buffer_size,
166 &data_request_call);
167
168 async_exchange_end(exch);
169
170 if (data_request == 0) {
171 async_forget(opening_request);
172 free(buffer);
173 return ENOMEM;
174 }
175
176 errno_t data_request_rc;
177 errno_t opening_request_rc;
178 async_wait_for(data_request, &data_request_rc);
179 async_wait_for(opening_request, &opening_request_rc);
180
181 if (data_request_rc != EOK) {
182 /* Prefer return code of the opening request. */
183 if (opening_request_rc != EOK)
184 return (errno_t) opening_request_rc;
185 else
186 return (errno_t) data_request_rc;
187 }
188
189 if (opening_request_rc != EOK)
190 return (errno_t) opening_request_rc;
191
192 size_t act_size = IPC_GET_ARG2(data_request_call);
193
194 /* Copy the individual items. */
195 memcpy(buf, buffer, act_size);
196
197 if (actual_size != NULL)
198 *actual_size = act_size;
199
200 if (event_nr != NULL)
201 *event_nr = IPC_GET_ARG1(opening_request_call);
202
203 return EOK;
204}
205
206errno_t usbhid_dev_get_report_descriptor_length(async_sess_t *dev_sess,
207 size_t *size)
208{
209 if (!dev_sess)
210 return EINVAL;
211
212 async_exch_t *exch = async_exchange_begin(dev_sess);
213
214 sysarg_t arg_size;
215 errno_t rc = async_req_1_1(exch, DEV_IFACE_ID(USBHID_DEV_IFACE),
216 IPC_M_USBHID_GET_REPORT_DESCRIPTOR_LENGTH, &arg_size);
217
218 async_exchange_end(exch);
219
220 if (rc == EOK) {
221 if (size != NULL)
222 *size = (size_t) arg_size;
223 }
224
225 return rc;
226}
227
228errno_t usbhid_dev_get_report_descriptor(async_sess_t *dev_sess, uint8_t *buf,
229 size_t size, size_t *actual_size)
230{
231 if (!dev_sess)
232 return EINVAL;
233
234 if (buf == NULL)
235 return ENOMEM;
236
237 if (size == 0)
238 return EINVAL;
239
240 async_exch_t *exch = async_exchange_begin(dev_sess);
241
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 }
249
250 ipc_call_t data_request_call;
251 aid_t data_request = async_data_read(exch, buf, size,
252 &data_request_call);
253
254 async_exchange_end(exch);
255
256 if (data_request == 0) {
257 async_forget(opening_request);
258 return ENOMEM;
259 }
260
261 errno_t data_request_rc;
262 errno_t opening_request_rc;
263 async_wait_for(data_request, &data_request_rc);
264 async_wait_for(opening_request, &opening_request_rc);
265
266 if (data_request_rc != EOK) {
267 /* Prefer return code of the opening request. */
268 if (opening_request_rc != EOK)
269 return (errno_t) opening_request_rc;
270 else
271 return (errno_t) data_request_rc;
272 }
273
274 if (opening_request_rc != EOK)
275 return (errno_t) opening_request_rc;
276
277 size_t act_size = IPC_GET_ARG2(data_request_call);
278
279 if (actual_size != NULL)
280 *actual_size = act_size;
281
282 return EOK;
283}
284
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 *);
289
290/** Remote USB HID interface operations. */
291static const remote_iface_func_ptr_t remote_usbhid_iface_ops [] = {
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
297};
298
299/** Remote USB HID interface structure.
300 */
301const remote_iface_t remote_usbhid_iface = {
302 .method_count = ARRAY_SIZE(remote_usbhid_iface_ops),
303 .methods = remote_usbhid_iface_ops
304};
305
306
307void remote_usbhid_get_event_length(ddf_fun_t *fun, void *iface,
308 ipc_call_t *call)
309{
310 printf("remote_usbhid_get_event_length()\n");
311
312 usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
313
314 if (!hid_iface->get_event_length) {
315 printf("Get event length not set!\n");
316 async_answer_0(call, ENOTSUP);
317 return;
318 }
319
320 size_t len = hid_iface->get_event_length(fun);
321 async_answer_1(call, EOK, len);
322}
323
324void remote_usbhid_get_event(ddf_fun_t *fun, void *iface,
325 ipc_call_t *call)
326{
327 usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
328
329 if (!hid_iface->get_event) {
330 async_answer_0(call, ENOTSUP);
331 return;
332 }
333
334 unsigned int flags = DEV_IPC_GET_ARG1(*call);
335
336 ipc_call_t data;
337 size_t len;
338 if (!async_data_read_receive(&data, &len)) {
339 async_answer_0(call, EPARTY);
340 return;
341 }
342
343 if (len == 0) {
344 async_answer_0(&data, EINVAL);
345 async_answer_0(call, EINVAL);
346 return;
347 }
348
349 errno_t rc;
350
351 uint8_t *event = malloc(len);
352 if (event == NULL) {
353 async_answer_0(&data, ENOMEM);
354 async_answer_0(call, ENOMEM);
355 return;
356 }
357
358 size_t act_length;
359 int event_nr;
360 rc = hid_iface->get_event(fun, event, len, &act_length, &event_nr, flags);
361 if (rc != EOK) {
362 free(event);
363 async_answer_0(&data, rc);
364 async_answer_0(call, rc);
365 return;
366 }
367 if (act_length >= len) {
368 /* This shall not happen. */
369 // FIXME: how about an assert here?
370 act_length = len;
371 }
372
373 async_data_read_finalize(&data, event, act_length);
374
375 free(event);
376
377 async_answer_1(call, EOK, event_nr);
378}
379
380void remote_usbhid_get_report_descriptor_length(ddf_fun_t *fun, void *iface,
381 ipc_call_t *call)
382{
383 usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
384
385 if (!hid_iface->get_report_descriptor_length) {
386 async_answer_0(call, ENOTSUP);
387 return;
388 }
389
390 size_t len = hid_iface->get_report_descriptor_length(fun);
391 async_answer_1(call, EOK, (sysarg_t) len);
392}
393
394void remote_usbhid_get_report_descriptor(ddf_fun_t *fun, void *iface,
395 ipc_call_t *call)
396{
397 usbhid_iface_t *hid_iface = (usbhid_iface_t *) iface;
398
399 if (!hid_iface->get_report_descriptor) {
400 async_answer_0(call, ENOTSUP);
401 return;
402 }
403
404 ipc_call_t data;
405 size_t len;
406 if (!async_data_read_receive(&data, &len)) {
407 async_answer_0(call, EINVAL);
408 return;
409 }
410
411 if (len == 0) {
412 async_answer_0(&data, EINVAL);
413 async_answer_0(call, EINVAL);
414 return;
415 }
416
417 uint8_t *descriptor = malloc(len);
418 if (descriptor == NULL) {
419 async_answer_0(&data, ENOMEM);
420 async_answer_0(call, ENOMEM);
421 return;
422 }
423
424 size_t act_len = 0;
425 errno_t rc = hid_iface->get_report_descriptor(fun, descriptor, len,
426 &act_len);
427 if (act_len > len) {
428 rc = ELIMIT;
429 }
430 if (rc != EOK) {
431 free(descriptor);
432 async_answer_0(&data, rc);
433 async_answer_0(call, rc);
434 return;
435 }
436
437 async_data_read_finalize(&data, descriptor, act_len);
438 async_answer_0(call, EOK);
439
440 free(descriptor);
441}
442
443/**
444 * @}
445 */
Note: See TracBrowser for help on using the repository browser.