source: mainline/uspace/drv/vhc/connhost.c@ 7034be15

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

First step to make virtual HC aware of DDF

Also, devman is automatically started on vt7.

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/*
2 * Copyright (c) 2010 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 usb
30 * @{
31 */
32/** @file
33 * @brief Connection handling of calls from host (implementation).
34 */
35#include <assert.h>
36#include <errno.h>
37#include <usb/hcd.h>
38
39#include "vhcd.h"
40#include "conn.h"
41#include "hc.h"
42
43typedef struct {
44 ipc_callid_t caller;
45 void *buffer;
46 size_t size;
47} async_transaction_t;
48
49static void async_out_callback(void * buffer, size_t len,
50 usb_transaction_outcome_t outcome, void * arg)
51{
52 async_transaction_t * trans = (async_transaction_t *)arg;
53
54 dprintf(2, "async_out_callback(buffer, %u, %d, %p) -> %x",
55 len, outcome, arg, trans->caller);
56
57 // FIXME - answer according to outcome
58 ipc_answer_1(trans->caller, EOK, 0);
59
60 free(trans);
61 if (buffer) {
62 free(buffer);
63 }
64 dprintf(4, "async_out_callback answered");
65}
66
67static void async_to_device(ipc_callid_t iid, ipc_call_t icall, bool setup_transaction)
68{
69 size_t expected_len = IPC_GET_ARG3(icall);
70 usb_target_t target = {
71 .address = IPC_GET_ARG1(icall),
72 .endpoint = IPC_GET_ARG2(icall)
73 };
74
75 dprintf(1, "async_to_device: dev=%d:%d, size=%d, iid=%x",
76 target.address, target.endpoint, expected_len, iid);
77
78 size_t len = 0;
79 void * buffer = NULL;
80 if (expected_len > 0) {
81 int rc = async_data_write_accept(&buffer, false,
82 1, USB_MAX_PAYLOAD_SIZE,
83 0, &len);
84
85 if (rc != EOK) {
86 ipc_answer_0(iid, rc);
87 return;
88 }
89 }
90
91 async_transaction_t * trans = malloc(sizeof(async_transaction_t));
92 trans->caller = iid;
93 trans->buffer = NULL;
94 trans->size = 0;
95
96 hc_add_transaction_to_device(setup_transaction, target,
97 buffer, len,
98 async_out_callback, trans);
99
100 dprintf(2, "async transaction to device scheduled (%p)", trans);
101}
102
103static void async_in_callback(void * buffer, size_t len,
104 usb_transaction_outcome_t outcome, void * arg)
105{
106 async_transaction_t * trans = (async_transaction_t *)arg;
107
108 dprintf(2, "async_in_callback(buffer, %u, %d, %p) -> %x",
109 len, outcome, arg, trans->caller);
110
111 trans->buffer = buffer;
112 trans->size = len;
113
114 ipc_callid_t caller = trans->caller;
115
116 if (buffer == NULL) {
117 free(trans);
118 trans = NULL;
119 }
120
121
122 // FIXME - answer according to outcome
123 ipc_answer_1(caller, EOK, (ipcarg_t)trans);
124 dprintf(4, "async_in_callback answered (%#x)", (ipcarg_t)trans);
125}
126
127static void async_from_device(ipc_callid_t iid, ipc_call_t icall)
128{
129 usb_target_t target = {
130 .address = IPC_GET_ARG1(icall),
131 .endpoint = IPC_GET_ARG2(icall)
132 };
133 size_t len = IPC_GET_ARG3(icall);
134
135 dprintf(1, "async_from_device: dev=%d:%d, size=%d, iid=%x",
136 target.address, target.endpoint, len, iid);
137
138 void * buffer = NULL;
139 if (len > 0) {
140 buffer = malloc(len);
141 }
142
143 async_transaction_t * trans = malloc(sizeof(async_transaction_t));
144 trans->caller = iid;
145 trans->buffer = NULL;
146 trans->size = 0;
147
148 hc_add_transaction_from_device(target,
149 buffer, len,
150 async_in_callback, trans);
151
152 dprintf(2, "async transfer from device scheduled (%p)", trans);
153}
154
155static void async_get_buffer(ipc_callid_t iid, ipc_call_t icall)
156{
157 ipcarg_t buffer_hash = IPC_GET_ARG1(icall);
158 async_transaction_t * trans = (async_transaction_t *)buffer_hash;
159 if (trans == NULL) {
160 ipc_answer_0(iid, ENOENT);
161 return;
162 }
163 if (trans->buffer == NULL) {
164 ipc_answer_0(iid, EINVAL);
165 free(trans);
166 return;
167 }
168
169 ipc_callid_t callid;
170 size_t accepted_size;
171 if (!async_data_read_receive(&callid, &accepted_size)) {
172 ipc_answer_0(iid, EINVAL);
173 return;
174 }
175
176 if (accepted_size > trans->size) {
177 accepted_size = trans->size;
178 }
179 async_data_read_finalize(callid, trans->buffer, accepted_size);
180
181 ipc_answer_1(iid, EOK, accepted_size);
182
183 free(trans->buffer);
184 free(trans);
185}
186
187
188/** Connection handler for communcation with host.
189 * By host is typically meant top-level USB driver.
190 *
191 * This function also takes care of proper phone hung-up.
192 *
193 * @param phone_hash Incoming phone hash.
194 */
195void connection_handler_host(ipcarg_t phone_hash)
196{
197 dprintf(0, "host connected through phone %#x", phone_hash);
198
199
200 while (true) {
201 ipc_callid_t callid;
202 ipc_call_t call;
203
204 callid = async_get_call(&call);
205
206 dprintf(6, "host on %#x calls [%x: %u (%u, %u, %u, %u, %u)]",
207 phone_hash,
208 callid,
209 IPC_GET_METHOD(call),
210 IPC_GET_ARG1(call), IPC_GET_ARG2(call), IPC_GET_ARG3(call),
211 IPC_GET_ARG4(call), IPC_GET_ARG5(call));
212
213 switch (IPC_GET_METHOD(call)) {
214
215 /* standard IPC methods */
216
217 case IPC_M_PHONE_HUNGUP:
218 ipc_answer_0(callid, EOK);
219 dprintf(0, "phone%#x: host hung-up",
220 phone_hash);
221 return;
222
223 case IPC_M_CONNECT_TO_ME:
224 ipc_answer_0(callid, ELIMIT);
225 break;
226
227
228 /* USB methods */
229
230 case IPC_M_USB_HCD_TRANSACTION_SIZE:
231 ipc_answer_1(callid, EOK, USB_MAX_PAYLOAD_SIZE);
232 break;
233
234 case IPC_M_USB_HCD_GET_BUFFER_ASYNC:
235 async_get_buffer(callid, call);
236 break;
237
238 case IPC_M_USB_HCD_INTERRUPT_OUT_ASYNC:
239 case IPC_M_USB_HCD_CONTROL_WRITE_DATA_ASYNC:
240 case IPC_M_USB_HCD_CONTROL_READ_STATUS_ASYNC:
241 async_to_device(callid, call, false);
242 break;
243
244 case IPC_M_USB_HCD_CONTROL_WRITE_SETUP_ASYNC:
245 case IPC_M_USB_HCD_CONTROL_READ_SETUP_ASYNC:
246 async_to_device(callid, call, true);
247 break;
248
249 case IPC_M_USB_HCD_INTERRUPT_IN_ASYNC:
250 case IPC_M_USB_HCD_CONTROL_WRITE_STATUS_ASYNC:
251 case IPC_M_USB_HCD_CONTROL_READ_DATA_ASYNC:
252 async_from_device(callid, call);
253 break;
254
255
256 /* end of known methods */
257
258 default:
259 dprintf_inval_call(2, call, phone_hash);
260 ipc_answer_0(callid, EINVAL);
261 break;
262 }
263 }
264}
265
266static int enqueue_transfer_out(usb_hc_device_t *hc,
267 usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
268 void *buffer, size_t size,
269 usb_hcd_transfer_callback_out_t callback, void *arg)
270{
271 printf(NAME ": transfer OUT [%d.%d (%s); %u]\n",
272 dev->address, endpoint->endpoint,
273 usb_str_transfer_type(endpoint->transfer_type),
274 size);
275 return ENOTSUP;
276}
277
278static int enqueue_transfer_setup(usb_hc_device_t *hc,
279 usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
280 void *buffer, size_t size,
281 usb_hcd_transfer_callback_out_t callback, void *arg)
282{
283 printf(NAME ": transfer SETUP [%d.%d (%s); %u]\n",
284 dev->address, endpoint->endpoint,
285 usb_str_transfer_type(endpoint->transfer_type),
286 size);
287 return ENOTSUP;
288}
289
290static int enqueue_transfer_in(usb_hc_device_t *hc,
291 usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
292 void *buffer, size_t size,
293 usb_hcd_transfer_callback_in_t callback, void *arg)
294{
295 printf(NAME ": transfer IN [%d.%d (%s); %u]\n",
296 dev->address, endpoint->endpoint,
297 usb_str_transfer_type(endpoint->transfer_type),
298 size);
299 return ENOTSUP;
300}
301
302
303usb_hcd_transfer_ops_t vhc_transfer_ops = {
304 .transfer_out = enqueue_transfer_out,
305 .transfer_in = enqueue_transfer_in,
306 .transfer_setup = enqueue_transfer_setup
307};
308
309/**
310 * @}
311 */
Note: See TracBrowser for help on using the repository browser.