source: mainline/uspace/lib/usbvirt/src/ipc_dev.c

Last change on this file was cdd6fc9, checked in by Jiri Svoboda <jiri@…>, 2 years ago

Add missing replies in IPC error paths

  • Property mode set to 100644
File size: 6.9 KB
RevLine 
[6cb58e6]1/*
[cdd6fc9]2 * Copyright (c) 2023 Jiri Svoboda
[6cb58e6]3 * Copyright (c) 2011 Vojtech Horky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libusbvirt
31 * @{
32 */
33/** @file
[e25a849]34 * IPC wrappers, device side.
[6cb58e6]35 */
36#include <errno.h>
37#include <str.h>
38#include <stdio.h>
39#include <assert.h>
40#include <async.h>
41#include <usbvirt/device.h>
42#include <usbvirt/ipc.h>
43#include <usb/debug.h>
44
[beee81a]45/** Handle VHC request for device name.
46 *
[984a9ba]47 * @param dev Target virtual device.
[beee81a]48 * @param icall The call with the request.
[984a9ba]49 *
[beee81a]50 */
[984a9ba]51static void ipc_get_name(usbvirt_device_t *dev, ipc_call_t *icall)
[6cb58e6]52{
53 if (dev->name == NULL) {
[984a9ba]54 async_answer_0(icall, ENOENT);
[6cb58e6]55 }
56
57 size_t size = str_size(dev->name);
58
[984a9ba]59 ipc_call_t call;
[6cb58e6]60 size_t accepted_size;
[984a9ba]61 if (!async_data_read_receive(&call, &accepted_size)) {
[cdd6fc9]62 async_answer_0(&call, EINVAL);
[984a9ba]63 async_answer_0(icall, EINVAL);
[6cb58e6]64 return;
65 }
66
67 if (accepted_size > size) {
68 accepted_size = size;
69 }
[984a9ba]70 async_data_read_finalize(&call, dev->name, accepted_size);
[6cb58e6]71
[984a9ba]72 async_answer_1(icall, EOK, accepted_size);
[6cb58e6]73}
74
[beee81a]75/** Handle VHC request for control read from the device.
76 *
[984a9ba]77 * @param dev Target virtual device.
[beee81a]78 * @param icall The call with the request.
[984a9ba]79 *
[beee81a]80 */
[984a9ba]81static void ipc_control_read(usbvirt_device_t *dev, ipc_call_t *icall)
[6cb58e6]82{
[b7fd2a0]83 errno_t rc;
[6cb58e6]84
85 void *setup_packet = NULL;
86 size_t setup_packet_len = 0;
87 size_t data_len = 0;
88
89 rc = async_data_write_accept(&setup_packet, false,
90 1, 1024, 0, &setup_packet_len);
91 if (rc != EOK) {
[984a9ba]92 async_answer_0(icall, rc);
[6cb58e6]93 return;
94 }
95
[984a9ba]96 ipc_call_t data;
97 if (!async_data_read_receive(&data, &data_len)) {
[cdd6fc9]98 async_answer_0(&data, EPARTY);
[984a9ba]99 async_answer_0(icall, EPARTY);
[6cb58e6]100 free(setup_packet);
101 return;
102 }
103
104 void *buffer = malloc(data_len);
105 if (buffer == NULL) {
[cdd6fc9]106 async_answer_0(&data, EPARTY);
[984a9ba]107 async_answer_0(icall, ENOMEM);
[6cb58e6]108 free(setup_packet);
109 return;
110 }
111
112 size_t actual_len;
113 rc = usbvirt_control_read(dev, setup_packet, setup_packet_len,
114 buffer, data_len, &actual_len);
115
116 if (rc != EOK) {
[984a9ba]117 async_answer_0(&data, rc);
118 async_answer_0(icall, rc);
[6cb58e6]119 free(setup_packet);
120 free(buffer);
121 return;
122 }
123
[984a9ba]124 async_data_read_finalize(&data, buffer, actual_len);
125 async_answer_0(icall, EOK);
[6cb58e6]126
127 free(setup_packet);
128 free(buffer);
129}
130
[beee81a]131/** Handle VHC request for control write to the device.
132 *
[984a9ba]133 * @param dev Target virtual device.
[beee81a]134 * @param icall The call with the request.
[984a9ba]135 *
[beee81a]136 */
[984a9ba]137static void ipc_control_write(usbvirt_device_t *dev, ipc_call_t *icall)
[6cb58e6]138{
[fafb8e5]139 size_t data_buffer_len = ipc_get_arg1(icall);
[b7fd2a0]140 errno_t rc;
[6cb58e6]141
142 void *setup_packet = NULL;
143 void *data_buffer = NULL;
144 size_t setup_packet_len = 0;
145
146 rc = async_data_write_accept(&setup_packet, false,
[beee81a]147 1, 0, 0, &setup_packet_len);
[6cb58e6]148 if (rc != EOK) {
[984a9ba]149 async_answer_0(icall, rc);
[6cb58e6]150 return;
151 }
152
153 if (data_buffer_len > 0) {
154 rc = async_data_write_accept(&data_buffer, false,
[beee81a]155 1, 0, 0, &data_buffer_len);
[6cb58e6]156 if (rc != EOK) {
[984a9ba]157 async_answer_0(icall, rc);
[6cb58e6]158 free(setup_packet);
159 return;
160 }
161 }
162
163 rc = usbvirt_control_write(dev, setup_packet, setup_packet_len,
164 data_buffer, data_buffer_len);
165
[984a9ba]166 async_answer_0(icall, rc);
[beee81a]167
168 free(setup_packet);
169 if (data_buffer != NULL) {
170 free(data_buffer);
171 }
[6cb58e6]172}
173
[beee81a]174/** Handle VHC request for data read from the device (in transfer).
175 *
[984a9ba]176 * @param dev Target virtual device.
[beee81a]177 * @param icall The call with the request.
[984a9ba]178 *
[beee81a]179 */
180static void ipc_data_in(usbvirt_device_t *dev,
[984a9ba]181 usb_transfer_type_t transfer_type, ipc_call_t *icall)
[6cb58e6]182{
[fafb8e5]183 usb_endpoint_t endpoint = ipc_get_arg1(icall);
[6cb58e6]184
[b7fd2a0]185 errno_t rc;
[6cb58e6]186
187 size_t data_len = 0;
[984a9ba]188 ipc_call_t data;
189 if (!async_data_read_receive(&data, &data_len)) {
[cdd6fc9]190 async_answer_0(&data, EPARTY);
[984a9ba]191 async_answer_0(icall, EPARTY);
[6cb58e6]192 return;
193 }
194
195 void *buffer = malloc(data_len);
196 if (buffer == NULL) {
[cdd6fc9]197 async_answer_0(&data, EPARTY);
[984a9ba]198 async_answer_0(icall, ENOMEM);
[6cb58e6]199 return;
200 }
201
202 size_t actual_len;
203 rc = usbvirt_data_in(dev, transfer_type, endpoint,
204 buffer, data_len, &actual_len);
205
206 if (rc != EOK) {
[984a9ba]207 async_answer_0(&data, rc);
208 async_answer_0(icall, rc);
[6cb58e6]209 free(buffer);
210 return;
211 }
212
[984a9ba]213 async_data_read_finalize(&data, buffer, actual_len);
214 async_answer_0(icall, EOK);
[6cb58e6]215
216 free(buffer);
217}
218
[beee81a]219/** Handle VHC request for data write to the device (out transfer).
220 *
[984a9ba]221 * @param dev Target virtual device.
[beee81a]222 * @param icall The call with the request.
[984a9ba]223 *
[beee81a]224 */
225static void ipc_data_out(usbvirt_device_t *dev,
[984a9ba]226 usb_transfer_type_t transfer_type, ipc_call_t *icall)
[6cb58e6]227{
[fafb8e5]228 usb_endpoint_t endpoint = ipc_get_arg1(icall);
[aa9a53d]229
230 void *data_buffer = NULL;
231 size_t data_buffer_size = 0;
232
[b7fd2a0]233 errno_t rc = async_data_write_accept(&data_buffer, false,
[beee81a]234 1, 0, 0, &data_buffer_size);
[aa9a53d]235 if (rc != EOK) {
[984a9ba]236 async_answer_0(icall, rc);
[aa9a53d]237 return;
238 }
239
240 rc = usbvirt_data_out(dev, transfer_type, endpoint,
241 data_buffer, data_buffer_size);
242
[984a9ba]243 async_answer_0(icall, rc);
[aa9a53d]244
245 free(data_buffer);
[6cb58e6]246}
247
[beee81a]248/** Handle incoming IPC call for virtual USB device.
249 *
[984a9ba]250 * @param dev Target USB device.
[beee81a]251 * @param call Incoming call.
[984a9ba]252 *
[beee81a]253 * @return Whether the call was handled.
[984a9ba]254 *
[beee81a]255 */
[984a9ba]256bool usbvirt_ipc_handle_call(usbvirt_device_t *dev, ipc_call_t *call)
[6cb58e6]257{
[fafb8e5]258 switch (ipc_get_imethod(call)) {
[beee81a]259 case IPC_M_USBVIRT_GET_NAME:
[984a9ba]260 ipc_get_name(dev, call);
[beee81a]261 break;
262
263 case IPC_M_USBVIRT_CONTROL_READ:
[984a9ba]264 ipc_control_read(dev, call);
[beee81a]265 break;
266
267 case IPC_M_USBVIRT_CONTROL_WRITE:
[984a9ba]268 ipc_control_write(dev, call);
[beee81a]269 break;
270
271 case IPC_M_USBVIRT_INTERRUPT_IN:
[984a9ba]272 ipc_data_in(dev, USB_TRANSFER_INTERRUPT, call);
[beee81a]273 break;
[6cb58e6]274
[beee81a]275 case IPC_M_USBVIRT_BULK_IN:
[984a9ba]276 ipc_data_in(dev, USB_TRANSFER_BULK, call);
[beee81a]277 break;
[6cb58e6]278
[beee81a]279 case IPC_M_USBVIRT_INTERRUPT_OUT:
[984a9ba]280 ipc_data_out(dev, USB_TRANSFER_INTERRUPT, call);
[beee81a]281 break;
[6cb58e6]282
[beee81a]283 case IPC_M_USBVIRT_BULK_OUT:
[984a9ba]284 ipc_data_out(dev, USB_TRANSFER_BULK, call);
[beee81a]285 break;
[6cb58e6]286
[beee81a]287 default:
288 return false;
[6cb58e6]289 }
290
291 return true;
292}
293
294/**
295 * @}
296 */
Note: See TracBrowser for help on using the repository browser.