source: mainline/uspace/lib/drv/generic/remote_usbhc.c@ 1a0fa29c

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

merge libdrv cleanup

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