source: mainline/uspace/lib/usbvirt/src/ipc_hc.c@ 25a179e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 25a179e was 25a179e, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

IPC return values are always errno constants. Adjust types to reflect that.

In principle, IPC server is not allowed to return non-errno values via
the "main" return value, because kernel interprets it (e.g. EHANGUP).
It's still possible to return arbitrary additional return values alongside EOK,
which are not interpreted in normal communication.

  • Property mode set to 100644
File size: 8.2 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 * IPC wrappers, host controller side.
34 */
35#include <errno.h>
36#include <str.h>
37#include <stdio.h>
38#include <assert.h>
39#include <async.h>
40#include <usbvirt/device.h>
41#include <usbvirt/ipc.h>
42#include <usb/debug.h>
43
44/** Send control read transfer to virtual USB device.
45 *
46 * @param sess Session to the virtual device.
47 * @param ep Target endpoint number.
48 * @param setup_buffer Setup buffer.
49 * @param setup_buffer_size Setup buffer size in bytes.
50 * @param data_buffer Data buffer (DATA stage of control transfer).
51 * @param data_buffer_size Size of data buffer in bytes.
52 * @param data_transfered_size Number of actually transferred bytes.
53 *
54 * @return Error code.
55 *
56 */
57int usbvirt_ipc_send_control_read(async_sess_t *sess, void *setup_buffer,
58 size_t setup_buffer_size, void *data_buffer, size_t data_buffer_size,
59 size_t *data_transfered_size)
60{
61 if (!sess)
62 return EINVAL;
63
64 if ((setup_buffer == NULL) || (setup_buffer_size == 0))
65 return EINVAL;
66
67 if ((data_buffer == NULL) || (data_buffer_size == 0))
68 return EINVAL;
69
70 async_exch_t *exch = async_exchange_begin(sess);
71
72 aid_t opening_request = async_send_0(exch, IPC_M_USBVIRT_CONTROL_READ,
73 NULL);
74 if (opening_request == 0) {
75 async_exchange_end(exch);
76 return ENOMEM;
77 }
78
79 int rc = async_data_write_start(exch, setup_buffer, setup_buffer_size);
80 if (rc != EOK) {
81 async_exchange_end(exch);
82 async_forget(opening_request);
83 return rc;
84 }
85
86 ipc_call_t data_request_call;
87 aid_t data_request = async_data_read(exch, data_buffer, data_buffer_size,
88 &data_request_call);
89
90 async_exchange_end(exch);
91
92 if (data_request == 0) {
93 async_forget(opening_request);
94 return ENOMEM;
95 }
96
97 int data_request_rc;
98 int opening_request_rc;
99 async_wait_for(data_request, &data_request_rc);
100 async_wait_for(opening_request, &opening_request_rc);
101
102 if (data_request_rc != EOK) {
103 /* Prefer the return code of the opening request. */
104 if (opening_request_rc != EOK)
105 return (int) opening_request_rc;
106 else
107 return (int) data_request_rc;
108 }
109
110 if (opening_request_rc != EOK)
111 return (int) opening_request_rc;
112
113 if (data_transfered_size != NULL)
114 *data_transfered_size = IPC_GET_ARG2(data_request_call);
115
116 return EOK;
117}
118
119/** Send control write transfer to virtual USB device.
120 *
121 * @param sess Session to the virtual device.
122 * @param ep Target endpoint number.
123 * @param setup_buffer Setup buffer.
124 * @param setup_buffer_size Setup buffer size in bytes.
125 * @param data_buffer Data buffer (DATA stage of control transfer).
126 * @param data_buffer_size Size of data buffer in bytes.
127 *
128 * @return Error code.
129 *
130 */
131int usbvirt_ipc_send_control_write(async_sess_t *sess, void *setup_buffer,
132 size_t setup_buffer_size, void *data_buffer, size_t data_buffer_size)
133{
134 if (!sess)
135 return EINVAL;
136
137 if ((setup_buffer == NULL) || (setup_buffer_size == 0))
138 return EINVAL;
139
140 if ((data_buffer_size > 0) && (data_buffer == NULL))
141 return EINVAL;
142
143 async_exch_t *exch = async_exchange_begin(sess);
144
145 aid_t opening_request = async_send_1(exch, IPC_M_USBVIRT_CONTROL_WRITE,
146 data_buffer_size, NULL);
147 if (opening_request == 0) {
148 async_exchange_end(exch);
149 return ENOMEM;
150 }
151
152 int rc = async_data_write_start(exch, setup_buffer, setup_buffer_size);
153 if (rc != EOK) {
154 async_exchange_end(exch);
155 async_forget(opening_request);
156 return rc;
157 }
158
159 if (data_buffer_size > 0) {
160 rc = async_data_write_start(exch, data_buffer, data_buffer_size);
161 if (rc != EOK) {
162 async_exchange_end(exch);
163 async_forget(opening_request);
164 return rc;
165 }
166 }
167
168 async_exchange_end(exch);
169
170 int opening_request_rc;
171 async_wait_for(opening_request, &opening_request_rc);
172
173 return (int) opening_request_rc;
174}
175
176/** Request data transfer from virtual USB device.
177 *
178 * @param sess Session to the virtual device.
179 * @param ep Target endpoint number.
180 * @param tr_type Transfer type (interrupt or bulk).
181 * @param data Data buffer.
182 * @param data_size Size of the data buffer in bytes.
183 * @param act_size Number of actually returned bytes.
184 *
185 * @return Error code.
186 *
187 */
188int usbvirt_ipc_send_data_in(async_sess_t *sess, usb_endpoint_t ep,
189 usb_transfer_type_t tr_type, void *data, size_t data_size, size_t *act_size)
190{
191 if (!sess)
192 return EINVAL;
193
194 usbvirt_hc_to_device_method_t method;
195
196 switch (tr_type) {
197 case USB_TRANSFER_INTERRUPT:
198 method = IPC_M_USBVIRT_INTERRUPT_IN;
199 break;
200 case USB_TRANSFER_BULK:
201 method = IPC_M_USBVIRT_BULK_IN;
202 break;
203 default:
204 return EINVAL;
205 }
206
207 if ((ep <= 0) || (ep >= USBVIRT_ENDPOINT_MAX))
208 return EINVAL;
209
210 if ((data == NULL) || (data_size == 0))
211 return EINVAL;
212
213 async_exch_t *exch = async_exchange_begin(sess);
214
215 aid_t opening_request = async_send_2(exch, method, ep, tr_type, NULL);
216 if (opening_request == 0) {
217 async_exchange_end(exch);
218 return ENOMEM;
219 }
220
221 ipc_call_t data_request_call;
222 aid_t data_request = async_data_read(exch, data, data_size,
223 &data_request_call);
224
225 async_exchange_end(exch);
226
227 if (data_request == 0) {
228 async_forget(opening_request);
229 return ENOMEM;
230 }
231
232 int data_request_rc;
233 int opening_request_rc;
234 async_wait_for(data_request, &data_request_rc);
235 async_wait_for(opening_request, &opening_request_rc);
236
237 if (data_request_rc != EOK) {
238 /* Prefer the return code of the opening request. */
239 if (opening_request_rc != EOK)
240 return (int) opening_request_rc;
241 else
242 return (int) data_request_rc;
243 }
244
245 if (opening_request_rc != EOK)
246 return (int) opening_request_rc;
247
248 if (act_size != NULL)
249 *act_size = IPC_GET_ARG2(data_request_call);
250
251 return EOK;
252}
253
254/** Send data to virtual USB device.
255 *
256 * @param sess Session to the virtual device.
257 * @param ep Target endpoint number.
258 * @param tr_type Transfer type (interrupt or bulk).
259 * @param data Data buffer.
260 * @param data_size Size of the data buffer in bytes.
261 *
262 * @return Error code.
263 *
264 */
265int usbvirt_ipc_send_data_out(async_sess_t *sess, usb_endpoint_t ep,
266 usb_transfer_type_t tr_type, void *data, size_t data_size)
267{
268 if (!sess)
269 return EINVAL;
270
271 usbvirt_hc_to_device_method_t method;
272
273 switch (tr_type) {
274 case USB_TRANSFER_INTERRUPT:
275 method = IPC_M_USBVIRT_INTERRUPT_OUT;
276 break;
277 case USB_TRANSFER_BULK:
278 method = IPC_M_USBVIRT_BULK_OUT;
279 break;
280 default:
281 return EINVAL;
282 }
283
284 if ((ep <= 0) || (ep >= USBVIRT_ENDPOINT_MAX))
285 return EINVAL;
286
287 if ((data == NULL) || (data_size == 0))
288 return EINVAL;
289
290 async_exch_t *exch = async_exchange_begin(sess);
291
292 aid_t opening_request = async_send_1(exch, method, ep, NULL);
293 if (opening_request == 0) {
294 async_exchange_end(exch);
295 return ENOMEM;
296 }
297
298 int rc = async_data_write_start(exch, data, data_size);
299
300 async_exchange_end(exch);
301
302 if (rc != EOK) {
303 async_forget(opening_request);
304 return rc;
305 }
306
307 int opening_request_rc;
308 async_wait_for(opening_request, &opening_request_rc);
309
310 return (int) opening_request_rc;
311}
312
313/**
314 * @}
315 */
Note: See TracBrowser for help on using the repository browser.