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

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

Virtual USB layer rewritten

Major changes include

  • IPC sends whole transfers (not transactions)
  • separate transfer queues for each device in host controller
  • possibility to return NAK from virtual device (handled by HC)
  • better implementation of callbacks for non-zero endpoints

Still missing

  • communication for some transfer types (bulk)
  • face-lift ;-)
  • documentation
  • Property mode set to 100644
File size: 9.6 KB
RevLine 
[6cb58e6]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 usb_log_debug("ipc_interrupt_in(.%d, %s)\n",
163 endpoint, usb_str_transfer_type_short(transfer_type));
164
165 int rc;
166
167 size_t data_len = 0;
168 ipc_callid_t data_callid;
169 if (!async_data_read_receive(&data_callid, &data_len)) {
170 async_answer_0(iid, EPARTY);
171 return;
172 }
173
174 void *buffer = malloc(data_len);
175 if (buffer == NULL) {
176 async_answer_0(iid, ENOMEM);
177 return;
178 }
179
180 size_t actual_len;
181 rc = usbvirt_data_in(dev, transfer_type, endpoint,
182 buffer, data_len, &actual_len);
183
184 if (rc != EOK) {
185 async_answer_0(data_callid, rc);
186 async_answer_0(iid, rc);
187 free(buffer);
188 return;
189 }
190
191 async_data_read_finalize(data_callid, buffer, actual_len);
192 async_answer_0(iid, EOK);
193
194 free(buffer);
195}
196
197static void ipc_interrupt_out(usbvirt_device_t *dev,
198 ipc_callid_t iid, ipc_call_t *icall)
199{
200 printf("ipc_interrupt_out()\n");
201 async_answer_0(iid, ENOTSUP);
202}
203
204
205bool usbvirt_ipc_handle_call(usbvirt_device_t *dev,
206 ipc_callid_t callid, ipc_call_t *call)
207{
208 switch (IPC_GET_IMETHOD(*call)) {
209 case IPC_M_USBVIRT_GET_NAME:
210 ipc_get_name(dev, callid, call);
211 break;
212
213 case IPC_M_USBVIRT_CONTROL_READ:
214 ipc_control_read(dev, callid, call);
215 break;
216
217 case IPC_M_USBVIRT_CONTROL_WRITE:
218 ipc_control_write(dev, callid, call);
219 break;
220
221 case IPC_M_USBVIRT_INTERRUPT_IN:
222 ipc_interrupt_in(dev, callid, call);
223 break;
224
225 case IPC_M_USBVIRT_INTERRUPT_OUT:
226 ipc_interrupt_out(dev, callid, call);
227 break;
228
229 default:
230 return false;
231 }
232
233 return true;
234}
235
236static void callback_connection(ipc_callid_t iid, ipc_call_t *icall)
237{
238 assert(DEV != NULL);
239
240 async_answer_0(iid, EOK);
241
242 while (true) {
243 ipc_callid_t callid;
244 ipc_call_t call;
245
246 callid = async_get_call(&call);
247 bool processed = usbvirt_ipc_handle_call(DEV, callid, &call);
248 if (!processed) {
249 switch (IPC_GET_IMETHOD(call)) {
250 case IPC_M_PHONE_HUNGUP:
251 async_answer_0(callid, EOK);
252 return;
253 default:
254 async_answer_0(callid, EINVAL);
255 break;
256 }
257 }
258 }
259}
260
261int usbvirt_device_plug(usbvirt_device_t *dev, const char *vhc_path)
262{
263 int rc;
264 devman_handle_t handle;
265
266 rc = devman_device_get_handle(vhc_path, &handle, 0);
267 if (rc != EOK) {
268 return rc;
269 }
270
271 int hcd_phone = devman_device_connect(handle, 0);
272
273 if (hcd_phone < 0) {
274 return hcd_phone;
275 }
276
277 DEV = dev;
278
279 rc = async_connect_to_me(hcd_phone, 0, 0, 0, callback_connection);
280 if (rc != EOK) {
281 DEV = NULL;
282 return rc;
283 }
284
285
286
287 return EOK;
288}
289
290
291
292int usbvirt_ipc_send_control_read(int phone, usb_endpoint_t ep,
293 void *setup_buffer, size_t setup_buffer_size,
294 void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
295{
296 aid_t opening_request = async_send_1(phone,
297 IPC_M_USBVIRT_CONTROL_READ, ep, NULL);
298 if (opening_request == 0) {
299 return ENOMEM;
300 }
301
302 int rc = async_data_write_start(phone,
303 setup_buffer, setup_buffer_size);
304 if (rc != EOK) {
305 async_wait_for(opening_request, NULL);
306 return rc;
307 }
308
309 ipc_call_t data_request_call;
310 aid_t data_request = async_data_read(phone,
311 data_buffer, data_buffer_size,
312 &data_request_call);
313
314 if (data_request == 0) {
315 async_wait_for(opening_request, NULL);
316 return ENOMEM;
317 }
318
319 sysarg_t data_request_rc;
320 sysarg_t opening_request_rc;
321 async_wait_for(data_request, &data_request_rc);
322 async_wait_for(opening_request, &opening_request_rc);
323
324 if (data_request_rc != EOK) {
325 /* Prefer the return code of the opening request. */
326 if (opening_request_rc != EOK) {
327 return (int) opening_request_rc;
328 } else {
329 return (int) data_request_rc;
330 }
331 }
332 if (opening_request_rc != EOK) {
333 return (int) opening_request_rc;
334 }
335
336 *data_transfered_size = IPC_GET_ARG2(data_request_call);
337
338 return EOK;
339}
340
341int usbvirt_ipc_send_control_write(int phone, usb_endpoint_t ep,
342 void *setup_buffer, size_t setup_buffer_size,
343 void *data_buffer, size_t data_buffer_size)
344{
345 aid_t opening_request = async_send_2(phone,
346 IPC_M_USBVIRT_CONTROL_WRITE, ep, data_buffer_size, NULL);
347 if (opening_request == 0) {
348 return ENOMEM;
349 }
350
351 int rc = async_data_write_start(phone,
352 setup_buffer, setup_buffer_size);
353 if (rc != EOK) {
354 async_wait_for(opening_request, NULL);
355 return rc;
356 }
357
358 if (data_buffer_size > 0) {
359 rc = async_data_write_start(phone,
360 data_buffer, data_buffer_size);
361
362 if (rc != EOK) {
363 async_wait_for(opening_request, NULL);
364 return rc;
365 }
366 }
367
368 sysarg_t opening_request_rc;
369 async_wait_for(opening_request, &opening_request_rc);
370
371 return (int) opening_request_rc;
372}
373
374int usbvirt_ipc_send_data_in(int phone, usb_endpoint_t ep,
375 usb_transfer_type_t tr_type, void *data, size_t data_size, size_t *act_size)
376{
377 aid_t opening_request = async_send_2(phone,
378 IPC_M_USBVIRT_INTERRUPT_IN, ep, tr_type, NULL);
379 if (opening_request == 0) {
380 return ENOMEM;
381 }
382
383 ipc_call_t data_request_call;
384 aid_t data_request = async_data_read(phone,
385 data, data_size, &data_request_call);
386
387 if (data_request == 0) {
388 async_wait_for(opening_request, NULL);
389 return ENOMEM;
390 }
391
392 sysarg_t data_request_rc;
393 sysarg_t opening_request_rc;
394 async_wait_for(data_request, &data_request_rc);
395 async_wait_for(opening_request, &opening_request_rc);
396
397 if (data_request_rc != EOK) {
398 /* Prefer the return code of the opening request. */
399 if (opening_request_rc != EOK) {
400 return (int) opening_request_rc;
401 } else {
402 return (int) data_request_rc;
403 }
404 }
405 if (opening_request_rc != EOK) {
406 return (int) opening_request_rc;
407 }
408
409 if (act_size != NULL) {
410 *act_size = IPC_GET_ARG2(data_request_call);
411 }
412
413 return EOK;
414}
415
416int usbvirt_ipc_send_data_out(int phone, usb_endpoint_t ep,
417 usb_transfer_type_t tr_type, void *data, size_t data_size)
418{
419 return ENOTSUP;
420}
421
422
423/**
424 * @}
425 */
Note: See TracBrowser for help on using the repository browser.