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

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

Virtual USB refactoring

Changes include

  • add missing comments
  • add function for virtual device disconnect
  • fix memory leak
  • support for bulks
  • checking of input parameters
  • Property mode set to 100644
File size: 7.0 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, device side.
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#include <usb/debug.h>
44
45/** Handle VHC request for device name.
46 *
47 * @param dev Target virtual device.
48 * @param iid Caller id.
49 * @param icall The call with the request.
50 */
51static void ipc_get_name(usbvirt_device_t *dev,
52 ipc_callid_t iid, ipc_call_t *icall)
53{
54 if (dev->name == NULL) {
55 async_answer_0(iid, ENOENT);
56 }
57
58 size_t size = str_size(dev->name);
59
60 ipc_callid_t callid;
61 size_t accepted_size;
62 if (!async_data_read_receive(&callid, &accepted_size)) {
63 async_answer_0(iid, EINVAL);
64 return;
65 }
66
67 if (accepted_size > size) {
68 accepted_size = size;
69 }
70 async_data_read_finalize(callid, dev->name, accepted_size);
71
72 async_answer_1(iid, EOK, accepted_size);
73}
74
75/** Handle VHC request for control read from the device.
76 *
77 * @param dev Target virtual device.
78 * @param iid Caller id.
79 * @param icall The call with the request.
80 */
81static void ipc_control_read(usbvirt_device_t *dev,
82 ipc_callid_t iid, ipc_call_t *icall)
83{
84 int rc;
85
86 void *setup_packet = NULL;
87 size_t setup_packet_len = 0;
88 size_t data_len = 0;
89
90 rc = async_data_write_accept(&setup_packet, false,
91 1, 1024, 0, &setup_packet_len);
92 if (rc != EOK) {
93 async_answer_0(iid, rc);
94 return;
95 }
96
97 ipc_callid_t data_callid;
98 if (!async_data_read_receive(&data_callid, &data_len)) {
99 async_answer_0(iid, EPARTY);
100 free(setup_packet);
101 return;
102 }
103
104 void *buffer = malloc(data_len);
105 if (buffer == NULL) {
106 async_answer_0(iid, ENOMEM);
107 free(setup_packet);
108 return;
109 }
110
111 size_t actual_len;
112 rc = usbvirt_control_read(dev, setup_packet, setup_packet_len,
113 buffer, data_len, &actual_len);
114
115 if (rc != EOK) {
116 async_answer_0(data_callid, rc);
117 async_answer_0(iid, rc);
118 free(setup_packet);
119 free(buffer);
120 return;
121 }
122
123 async_data_read_finalize(data_callid, buffer, actual_len);
124 async_answer_0(iid, EOK);
125
126 free(setup_packet);
127 free(buffer);
128}
129
130/** Handle VHC request for control write to the device.
131 *
132 * @param dev Target virtual device.
133 * @param iid Caller id.
134 * @param icall The call with the request.
135 */
136static void ipc_control_write(usbvirt_device_t *dev,
137 ipc_callid_t iid, ipc_call_t *icall)
138{
139 size_t data_buffer_len = IPC_GET_ARG1(*icall);
140 int rc;
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,
147 1, 0, 0, &setup_packet_len);
148 if (rc != EOK) {
149 async_answer_0(iid, rc);
150 return;
151 }
152
153 if (data_buffer_len > 0) {
154 rc = async_data_write_accept(&data_buffer, false,
155 1, 0, 0, &data_buffer_len);
156 if (rc != EOK) {
157 async_answer_0(iid, rc);
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
166 async_answer_0(iid, rc);
167
168 free(setup_packet);
169 if (data_buffer != NULL) {
170 free(data_buffer);
171 }
172}
173
174/** Handle VHC request for data read from the device (in transfer).
175 *
176 * @param dev Target virtual device.
177 * @param iid Caller id.
178 * @param icall The call with the request.
179 */
180static void ipc_data_in(usbvirt_device_t *dev,
181 usb_transfer_type_t transfer_type,
182 ipc_callid_t iid, ipc_call_t *icall)
183{
184 usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
185
186 int rc;
187
188 size_t data_len = 0;
189 ipc_callid_t data_callid;
190 if (!async_data_read_receive(&data_callid, &data_len)) {
191 async_answer_0(iid, EPARTY);
192 return;
193 }
194
195 void *buffer = malloc(data_len);
196 if (buffer == NULL) {
197 async_answer_0(iid, ENOMEM);
198 return;
199 }
200
201 size_t actual_len;
202 rc = usbvirt_data_in(dev, transfer_type, endpoint,
203 buffer, data_len, &actual_len);
204
205 if (rc != EOK) {
206 async_answer_0(data_callid, rc);
207 async_answer_0(iid, rc);
208 free(buffer);
209 return;
210 }
211
212 async_data_read_finalize(data_callid, buffer, actual_len);
213 async_answer_0(iid, EOK);
214
215 free(buffer);
216}
217
218/** Handle VHC request for data write to the device (out transfer).
219 *
220 * @param dev Target virtual device.
221 * @param iid Caller id.
222 * @param icall The call with the request.
223 */
224static void ipc_data_out(usbvirt_device_t *dev,
225 usb_transfer_type_t transfer_type,
226 ipc_callid_t iid, ipc_call_t *icall)
227{
228 usb_endpoint_t endpoint = IPC_GET_ARG1(*icall);
229
230 void *data_buffer = NULL;
231 size_t data_buffer_size = 0;
232
233 int rc = async_data_write_accept(&data_buffer, false,
234 1, 0, 0, &data_buffer_size);
235 if (rc != EOK) {
236 async_answer_0(iid, rc);
237 return;
238 }
239
240 rc = usbvirt_data_out(dev, transfer_type, endpoint,
241 data_buffer, data_buffer_size);
242
243 async_answer_0(iid, rc);
244
245 free(data_buffer);
246}
247
248/** Handle incoming IPC call for virtual USB device.
249 *
250 * @param dev Target USB device.
251 * @param callid Caller id.
252 * @param call Incoming call.
253 * @return Whether the call was handled.
254 */
255bool usbvirt_ipc_handle_call(usbvirt_device_t *dev,
256 ipc_callid_t callid, ipc_call_t *call)
257{
258 switch (IPC_GET_IMETHOD(*call)) {
259 case IPC_M_USBVIRT_GET_NAME:
260 ipc_get_name(dev, callid, call);
261 break;
262
263 case IPC_M_USBVIRT_CONTROL_READ:
264 ipc_control_read(dev, callid, call);
265 break;
266
267 case IPC_M_USBVIRT_CONTROL_WRITE:
268 ipc_control_write(dev, callid, call);
269 break;
270
271 case IPC_M_USBVIRT_INTERRUPT_IN:
272 ipc_data_in(dev, USB_TRANSFER_INTERRUPT, callid, call);
273 break;
274
275 case IPC_M_USBVIRT_BULK_IN:
276 ipc_data_in(dev, USB_TRANSFER_BULK, callid, call);
277 break;
278
279 case IPC_M_USBVIRT_INTERRUPT_OUT:
280 ipc_data_out(dev, USB_TRANSFER_INTERRUPT, callid, call);
281 break;
282
283 case IPC_M_USBVIRT_BULK_OUT:
284 ipc_data_out(dev, USB_TRANSFER_BULK, callid, call);
285 break;
286
287
288 default:
289 return false;
290 }
291
292 return true;
293}
294
295/**
296 * @}
297 */
Note: See TracBrowser for help on using the repository browser.