source: mainline/uspace/lib/drv/generic/remote_usbhc.c@ 7c10198

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7c10198 was 7c10198, checked in by Jan Vesely <jano.vesely@…>, 12 years ago

libdrv: Remove usb enpoint register/unregister from usb hc iface

nothing is using this, and nothing should

  • Property mode set to 100644
File size: 9.8 KB
Line 
1/*
2 * Copyright (c) 2010-2011 Vojtech Horky
3 * Copyright (c) 2011 Jan Vesely
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 libdrv
31 * @{
32 */
33/** @file
34 */
35
36#include <async.h>
37#include <errno.h>
38#include <assert.h>
39
40#include "usbhc_iface.h"
41#include "ddf/driver.h"
42
43#define USB_MAX_PAYLOAD_SIZE 1020
44
45/** IPC methods for communication with HC through DDF interface.
46 *
47 * Notes for async methods:
48 *
49 * Methods for sending data to device (OUT transactions)
50 * - e.g. IPC_M_USBHC_INTERRUPT_OUT -
51 * always use the same semantics:
52 * - first, IPC call with given method is made
53 * - argument #1 is target address
54 * - argument #2 is target endpoint
55 * - argument #3 is max packet size of the endpoint
56 * - this call is immediately followed by IPC data write (from caller)
57 * - the initial call (and the whole transaction) is answer after the
58 * transaction is scheduled by the HC and acknowledged by the device
59 * or immediately after error is detected
60 * - the answer carries only the error code
61 *
62 * Methods for retrieving data from device (IN transactions)
63 * - e.g. IPC_M_USBHC_INTERRUPT_IN -
64 * also use the same semantics:
65 * - first, IPC call with given method is made
66 * - argument #1 is target address
67 * - argument #2 is target endpoint
68 * - this call is immediately followed by IPC data read (async version)
69 * - the call is not answered until the device returns some data (or until
70 * error occurs)
71 *
72 * Some special methods (NO-DATA transactions) do not send any data. These
73 * might behave as both OUT or IN transactions because communication parts
74 * where actual buffers are exchanged are omitted.
75 **
76 * For all these methods, wrap functions exists. Important rule: functions
77 * for IN transactions have (as parameters) buffers where retrieved data
78 * will be stored. These buffers must be already allocated and shall not be
79 * touch until the transaction is completed
80 * (e.g. not before calling usb_wait_for() with appropriate handle).
81 * OUT transactions buffers can be freed immediately after call is dispatched
82 * (i.e. after return from wrapping function).
83 *
84 */
85typedef enum {
86 /** Get data from device.
87 * See explanation at usb_iface_funcs_t (IN transaction).
88 */
89 IPC_M_USBHC_READ,
90
91 /** Send data to device.
92 * See explanation at usb_iface_funcs_t (OUT transaction).
93 */
94 IPC_M_USBHC_WRITE,
95} usbhc_iface_funcs_t;
96
97int usbhc_read(async_exch_t *exch, usb_address_t address,
98 usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size,
99 size_t *rec_size)
100{
101 if (!exch)
102 return EBADMEM;
103
104 if (size == 0 && setup == 0)
105 return EOK;
106
107 const usb_target_t target =
108 {{ .address = address, .endpoint = endpoint }};
109
110 /* Make call identifying target USB device and type of transfer. */
111 aid_t opening_request = async_send_4(exch,
112 DEV_IFACE_ID(USBHC_DEV_IFACE),
113 IPC_M_USBHC_READ, target.packed,
114 (setup & UINT32_MAX), (setup >> 32), NULL);
115
116 if (opening_request == 0) {
117 return ENOMEM;
118 }
119
120 /* Retrieve the data. */
121 ipc_call_t data_request_call;
122 aid_t data_request =
123 async_data_read(exch, data, size, &data_request_call);
124
125 if (data_request == 0) {
126 // FIXME: How to let the other side know that we want to abort?
127 async_forget(opening_request);
128 return ENOMEM;
129 }
130
131 /* Wait for the answer. */
132 sysarg_t data_request_rc;
133 sysarg_t opening_request_rc;
134 async_wait_for(data_request, &data_request_rc);
135 async_wait_for(opening_request, &opening_request_rc);
136
137 if (data_request_rc != EOK) {
138 /* Prefer the return code of the opening request. */
139 if (opening_request_rc != EOK) {
140 return (int) opening_request_rc;
141 } else {
142 return (int) data_request_rc;
143 }
144 }
145 if (opening_request_rc != EOK) {
146 return (int) opening_request_rc;
147 }
148
149 *rec_size = IPC_GET_ARG2(data_request_call);
150 return EOK;
151}
152
153int usbhc_write(async_exch_t *exch, usb_address_t address,
154 usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size)
155{
156 if (!exch)
157 return EBADMEM;
158
159 if (size == 0 && setup == 0)
160 return EOK;
161
162 const usb_target_t target =
163 {{ .address = address, .endpoint = endpoint }};
164
165 aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
166 IPC_M_USBHC_WRITE, target.packed, size,
167 (setup & UINT32_MAX), (setup >> 32), NULL);
168
169 if (opening_request == 0) {
170 return ENOMEM;
171 }
172
173 /* Send the data if any. */
174 if (size > 0) {
175 const int ret = async_data_write_start(exch, data, size);
176 if (ret != EOK) {
177 async_forget(opening_request);
178 return ret;
179 }
180 }
181
182 /* Wait for the answer. */
183 sysarg_t opening_request_rc;
184 async_wait_for(opening_request, &opening_request_rc);
185
186 return (int) opening_request_rc;
187}
188
189static void remote_usbhc_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
190static void remote_usbhc_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
191
192/** Remote USB host controller interface operations. */
193static remote_iface_func_ptr_t remote_usbhc_iface_ops[] = {
194 [IPC_M_USBHC_READ] = remote_usbhc_read,
195 [IPC_M_USBHC_WRITE] = remote_usbhc_write,
196};
197
198/** Remote USB host controller interface structure.
199 */
200remote_iface_t remote_usbhc_iface = {
201 .method_count = sizeof(remote_usbhc_iface_ops) /
202 sizeof(remote_usbhc_iface_ops[0]),
203 .methods = remote_usbhc_iface_ops
204};
205
206typedef struct {
207 ipc_callid_t caller;
208 ipc_callid_t data_caller;
209 void *buffer;
210} async_transaction_t;
211
212static void async_transaction_destroy(async_transaction_t *trans)
213{
214 if (trans == NULL) {
215 return;
216 }
217 if (trans->buffer != NULL) {
218 free(trans->buffer);
219 }
220
221 free(trans);
222}
223
224static async_transaction_t *async_transaction_create(ipc_callid_t caller)
225{
226 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
227 if (trans == NULL) {
228 return NULL;
229 }
230
231 trans->caller = caller;
232 trans->data_caller = 0;
233 trans->buffer = NULL;
234
235 return trans;
236}
237
238static void callback_out(int outcome, void *arg)
239{
240 async_transaction_t *trans = arg;
241
242 async_answer_0(trans->caller, outcome);
243
244 async_transaction_destroy(trans);
245}
246
247static void callback_in(int outcome, size_t actual_size, void *arg)
248{
249 async_transaction_t *trans = (async_transaction_t *)arg;
250
251 if (outcome != EOK) {
252 async_answer_0(trans->caller, outcome);
253 if (trans->data_caller) {
254 async_answer_0(trans->data_caller, EINTR);
255 }
256 async_transaction_destroy(trans);
257 return;
258 }
259
260 if (trans->data_caller) {
261 async_data_read_finalize(trans->data_caller,
262 trans->buffer, actual_size);
263 }
264
265 async_answer_0(trans->caller, EOK);
266
267 async_transaction_destroy(trans);
268}
269
270void remote_usbhc_read(
271 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
272{
273 assert(fun);
274 assert(iface);
275 assert(call);
276
277 const usbhc_iface_t *hc_iface = iface;
278
279 if (!hc_iface->read) {
280 async_answer_0(callid, ENOTSUP);
281 return;
282 }
283
284 const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
285 const uint64_t setup =
286 ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
287 (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
288
289 async_transaction_t *trans = async_transaction_create(callid);
290 if (trans == NULL) {
291 async_answer_0(callid, ENOMEM);
292 return;
293 }
294
295 size_t size = 0;
296 if (!async_data_read_receive(&trans->data_caller, &size)) {
297 async_answer_0(callid, EPARTY);
298 return;
299 }
300
301 trans->buffer = malloc(size);
302 if (trans->buffer == NULL) {
303 async_answer_0(trans->data_caller, ENOMEM);
304 async_answer_0(callid, ENOMEM);
305 async_transaction_destroy(trans);
306 }
307
308 const int rc = hc_iface->read(
309 fun, target, setup, trans->buffer, size, callback_in, trans);
310
311 if (rc != EOK) {
312 async_answer_0(trans->data_caller, rc);
313 async_answer_0(callid, rc);
314 async_transaction_destroy(trans);
315 }
316}
317
318void remote_usbhc_write(
319 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
320{
321 assert(fun);
322 assert(iface);
323 assert(call);
324
325 const usbhc_iface_t *hc_iface = iface;
326
327 if (!hc_iface->write) {
328 async_answer_0(callid, ENOTSUP);
329 return;
330 }
331
332 const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
333 const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
334 const uint64_t setup =
335 ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
336 (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
337
338 async_transaction_t *trans = async_transaction_create(callid);
339 if (trans == NULL) {
340 async_answer_0(callid, ENOMEM);
341 return;
342 }
343
344 size_t size = 0;
345 if (data_buffer_len > 0) {
346 const int rc = async_data_write_accept(&trans->buffer, false,
347 1, USB_MAX_PAYLOAD_SIZE,
348 0, &size);
349
350 if (rc != EOK) {
351 async_answer_0(callid, rc);
352 async_transaction_destroy(trans);
353 return;
354 }
355 }
356
357 const int rc = hc_iface->write(
358 fun, target, setup, trans->buffer, size, callback_out, trans);
359
360 if (rc != EOK) {
361 async_answer_0(callid, rc);
362 async_transaction_destroy(trans);
363 }
364}
365/**
366 * @}
367 */
Note: See TracBrowser for help on using the repository browser.