source: mainline/uspace/lib/usbvirt/src/ipc.c@ dc06caa

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since dc06caa was dc06caa, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

More comments in libusbvirt

  • Property mode set to 100644
File size: 10.5 KB
Line 
1/*
2 * Copyright (c) 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 libusbvirt
30 * @{
31 */
32/** @file
33 *
34 */
35#include <errno.h>
36#include <str.h>
37#include <stdio.h>
38#include <assert.h>
39#include <async.h>
40#include <devman.h>
41#include <usbvirt/device.h>
42#include <usbvirt/ipc.h>
43
44#include <usb/debug.h>
45
46static usbvirt_device_t *DEV = NULL;
47
48static void ipc_get_name(usbvirt_device_t *dev,
49 ipc_callid_t iid, ipc_call_t *icall)
50{
51 if (dev->name == NULL) {
52 async_answer_0(iid, ENOENT);
53 }
54
55 size_t size = str_size(dev->name);
56
57 ipc_callid_t callid;
58 size_t accepted_size;
59 if (!async_data_read_receive(&callid, &accepted_size)) {
60 async_answer_0(iid, EINVAL);
61 return;
62 }
63
64 if (accepted_size > size) {
65 accepted_size = size;
66 }
67 async_data_read_finalize(callid, dev->name, accepted_size);
68
69 async_answer_1(iid, EOK, accepted_size);
70}
71
72static void ipc_control_read(usbvirt_device_t *dev,
73 ipc_callid_t iid, ipc_call_t *icall)
74{
75 //usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
76
77 int rc;
78
79 void *setup_packet = NULL;
80 size_t setup_packet_len = 0;
81 size_t data_len = 0;
82
83 rc = async_data_write_accept(&setup_packet, false,
84 1, 1024, 0, &setup_packet_len);
85 if (rc != EOK) {
86 async_answer_0(iid, rc);
87 return;
88 }
89
90 ipc_callid_t data_callid;
91 if (!async_data_read_receive(&data_callid, &data_len)) {
92 async_answer_0(iid, EPARTY);
93 free(setup_packet);
94 return;
95 }
96
97 void *buffer = malloc(data_len);
98 if (buffer == NULL) {
99 async_answer_0(iid, ENOMEM);
100 free(setup_packet);
101 return;
102 }
103
104 size_t actual_len;
105 rc = usbvirt_control_read(dev, setup_packet, setup_packet_len,
106 buffer, data_len, &actual_len);
107
108 if (rc != EOK) {
109 async_answer_0(data_callid, rc);
110 async_answer_0(iid, rc);
111 free(setup_packet);
112 free(buffer);
113 return;
114 }
115
116 async_data_read_finalize(data_callid, buffer, actual_len);
117 async_answer_0(iid, EOK);
118
119 free(setup_packet);
120 free(buffer);
121}
122
123static void ipc_control_write(usbvirt_device_t *dev,
124 ipc_callid_t iid, ipc_call_t *icall)
125{
126 size_t data_buffer_len = IPC_GET_ARG2(*icall);
127 int rc;
128
129 void *setup_packet = NULL;
130 void *data_buffer = NULL;
131 size_t setup_packet_len = 0;
132
133 rc = async_data_write_accept(&setup_packet, false,
134 1, 1024, 0, &setup_packet_len);
135 if (rc != EOK) {
136 async_answer_0(iid, rc);
137 return;
138 }
139
140 if (data_buffer_len > 0) {
141 rc = async_data_write_accept(&data_buffer, false,
142 1, 1024, 0, &data_buffer_len);
143 if (rc != EOK) {
144 async_answer_0(iid, rc);
145 free(setup_packet);
146 return;
147 }
148 }
149
150 rc = usbvirt_control_write(dev, setup_packet, setup_packet_len,
151 data_buffer, data_buffer_len);
152
153 async_answer_0(iid, rc);
154}
155
156static void ipc_interrupt_in(usbvirt_device_t *dev,
157 ipc_callid_t iid, ipc_call_t *icall)
158{
159 usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
160 usb_transfer_type_t transfer_type = IPC_GET_ARG2(*icall);
161
162 int rc;
163
164 size_t data_len = 0;
165 ipc_callid_t data_callid;
166 if (!async_data_read_receive(&data_callid, &data_len)) {
167 async_answer_0(iid, EPARTY);
168 return;
169 }
170
171 void *buffer = malloc(data_len);
172 if (buffer == NULL) {
173 async_answer_0(iid, ENOMEM);
174 return;
175 }
176
177 size_t actual_len;
178 rc = usbvirt_data_in(dev, transfer_type, endpoint,
179 buffer, data_len, &actual_len);
180
181 if (rc != EOK) {
182 async_answer_0(data_callid, rc);
183 async_answer_0(iid, rc);
184 free(buffer);
185 return;
186 }
187
188 async_data_read_finalize(data_callid, buffer, actual_len);
189 async_answer_0(iid, EOK);
190
191 free(buffer);
192}
193
194static void ipc_interrupt_out(usbvirt_device_t *dev,
195 ipc_callid_t iid, ipc_call_t *icall)
196{
197 usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
198 usb_transfer_type_t transfer_type = IPC_GET_ARG2(*icall);
199
200 void *data_buffer = NULL;
201 size_t data_buffer_size = 0;
202
203 int rc = async_data_write_accept(&data_buffer, false,
204 1, 1024, 0, &data_buffer_size);
205 if (rc != EOK) {
206 async_answer_0(iid, rc);
207 return;
208 }
209
210 rc = usbvirt_data_out(dev, transfer_type, endpoint,
211 data_buffer, data_buffer_size);
212
213 async_answer_0(iid, rc);
214
215 free(data_buffer);
216}
217
218
219bool usbvirt_ipc_handle_call(usbvirt_device_t *dev,
220 ipc_callid_t callid, ipc_call_t *call)
221{
222 switch (IPC_GET_IMETHOD(*call)) {
223 case IPC_M_USBVIRT_GET_NAME:
224 ipc_get_name(dev, callid, call);
225 break;
226
227 case IPC_M_USBVIRT_CONTROL_READ:
228 ipc_control_read(dev, callid, call);
229 break;
230
231 case IPC_M_USBVIRT_CONTROL_WRITE:
232 ipc_control_write(dev, callid, call);
233 break;
234
235 case IPC_M_USBVIRT_INTERRUPT_IN:
236 ipc_interrupt_in(dev, callid, call);
237 break;
238
239 case IPC_M_USBVIRT_INTERRUPT_OUT:
240 ipc_interrupt_out(dev, callid, call);
241 break;
242
243 default:
244 return false;
245 }
246
247 return true;
248}
249
250static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
251{
252 assert(DEV != NULL);
253
254 async_answer_0(iid, EOK);
255
256 while (true) {
257 ipc_callid_t callid;
258 ipc_call_t call;
259
260 callid = async_get_call(&call);
261 bool processed = usbvirt_ipc_handle_call(DEV, callid, &call);
262 if (!processed) {
263 switch (IPC_GET_IMETHOD(call)) {
264 case IPC_M_PHONE_HUNGUP:
265 async_answer_0(callid, EOK);
266 return;
267 default:
268 async_answer_0(callid, EINVAL);
269 break;
270 }
271 }
272 }
273}
274
275/** Connect the device to the virtual host controller.
276 *
277 * @param dev The virtual device to be (virtually) plugged in.
278 * @param vhc_path Devman path to the virtual host controller.
279 * @return Error code.
280 */
281int usbvirt_device_plug(usbvirt_device_t *dev, const char *vhc_path)
282{
283 int rc;
284 devman_handle_t handle;
285
286 rc = devman_device_get_handle(vhc_path, &handle, 0);
287 if (rc != EOK) {
288 return rc;
289 }
290
291 int hcd_phone = devman_device_connect(handle, 0);
292
293 if (hcd_phone < 0) {
294 return hcd_phone;
295 }
296
297 DEV = dev;
298
299 rc = async_connect_to_me(hcd_phone, 0, 0, 0, callback_connection);
300 if (rc != EOK) {
301 DEV = NULL;
302 return rc;
303 }
304
305
306
307 return EOK;
308}
309
310
311
312int usbvirt_ipc_send_control_read(int phone, usb_endpoint_t ep,
313 void *setup_buffer, size_t setup_buffer_size,
314 void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
315{
316 aid_t opening_request = async_send_1(phone,
317 IPC_M_USBVIRT_CONTROL_READ, ep, NULL);
318 if (opening_request == 0) {
319 return ENOMEM;
320 }
321
322 int rc = async_data_write_start(phone,
323 setup_buffer, setup_buffer_size);
324 if (rc != EOK) {
325 async_wait_for(opening_request, NULL);
326 return rc;
327 }
328
329 ipc_call_t data_request_call;
330 aid_t data_request = async_data_read(phone,
331 data_buffer, data_buffer_size,
332 &data_request_call);
333
334 if (data_request == 0) {
335 async_wait_for(opening_request, NULL);
336 return ENOMEM;
337 }
338
339 sysarg_t data_request_rc;
340 sysarg_t opening_request_rc;
341 async_wait_for(data_request, &data_request_rc);
342 async_wait_for(opening_request, &opening_request_rc);
343
344 if (data_request_rc != EOK) {
345 /* Prefer the return code of the opening request. */
346 if (opening_request_rc != EOK) {
347 return (int) opening_request_rc;
348 } else {
349 return (int) data_request_rc;
350 }
351 }
352 if (opening_request_rc != EOK) {
353 return (int) opening_request_rc;
354 }
355
356 *data_transfered_size = IPC_GET_ARG2(data_request_call);
357
358 return EOK;
359}
360
361int usbvirt_ipc_send_control_write(int phone, usb_endpoint_t ep,
362 void *setup_buffer, size_t setup_buffer_size,
363 void *data_buffer, size_t data_buffer_size)
364{
365 aid_t opening_request = async_send_2(phone,
366 IPC_M_USBVIRT_CONTROL_WRITE, ep, data_buffer_size, NULL);
367 if (opening_request == 0) {
368 return ENOMEM;
369 }
370
371 int rc = async_data_write_start(phone,
372 setup_buffer, setup_buffer_size);
373 if (rc != EOK) {
374 async_wait_for(opening_request, NULL);
375 return rc;
376 }
377
378 if (data_buffer_size > 0) {
379 rc = async_data_write_start(phone,
380 data_buffer, data_buffer_size);
381
382 if (rc != EOK) {
383 async_wait_for(opening_request, NULL);
384 return rc;
385 }
386 }
387
388 sysarg_t opening_request_rc;
389 async_wait_for(opening_request, &opening_request_rc);
390
391 return (int) opening_request_rc;
392}
393
394int usbvirt_ipc_send_data_in(int phone, usb_endpoint_t ep,
395 usb_transfer_type_t tr_type, void *data, size_t data_size, size_t *act_size)
396{
397 aid_t opening_request = async_send_2(phone,
398 IPC_M_USBVIRT_INTERRUPT_IN, ep, tr_type, NULL);
399 if (opening_request == 0) {
400 return ENOMEM;
401 }
402
403 ipc_call_t data_request_call;
404 aid_t data_request = async_data_read(phone,
405 data, data_size, &data_request_call);
406
407 if (data_request == 0) {
408 async_wait_for(opening_request, NULL);
409 return ENOMEM;
410 }
411
412 sysarg_t data_request_rc;
413 sysarg_t opening_request_rc;
414 async_wait_for(data_request, &data_request_rc);
415 async_wait_for(opening_request, &opening_request_rc);
416
417 if (data_request_rc != EOK) {
418 /* Prefer the return code of the opening request. */
419 if (opening_request_rc != EOK) {
420 return (int) opening_request_rc;
421 } else {
422 return (int) data_request_rc;
423 }
424 }
425 if (opening_request_rc != EOK) {
426 return (int) opening_request_rc;
427 }
428
429 if (act_size != NULL) {
430 *act_size = IPC_GET_ARG2(data_request_call);
431 }
432
433 return EOK;
434}
435
436int usbvirt_ipc_send_data_out(int phone, usb_endpoint_t ep,
437 usb_transfer_type_t tr_type, void *data, size_t data_size)
438{
439 aid_t opening_request = async_send_2(phone,
440 IPC_M_USBVIRT_INTERRUPT_OUT, ep, tr_type, NULL);
441 if (opening_request == 0) {
442 return ENOMEM;
443 }
444
445 int rc = async_data_write_start(phone,
446 data, data_size);
447 if (rc != EOK) {
448 async_wait_for(opening_request, NULL);
449 return rc;
450 }
451
452 sysarg_t opening_request_rc;
453 async_wait_for(opening_request, &opening_request_rc);
454
455 return (int) opening_request_rc;
456}
457
458
459/**
460 * @}
461 */
Note: See TracBrowser for help on using the repository browser.