source: mainline/uspace/lib/drv/generic/remote_usbhc.c@ 2fd26bb

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

merge mainline changes

most usb changes were reverted. blink and usbmass were fixed
known problems:
ehci won't initialize
usbmast asserts on unmount (happens on mainline too)

  • 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{
[99172baf]214 if (trans == NULL)
[93f8da1]215 return;
[99172baf]216
217 if (trans->buffer != NULL)
[93f8da1]218 free(trans->buffer);
[99172baf]219
[93f8da1]220 free(trans);
221}
222
223static async_transaction_t *async_transaction_create(ipc_callid_t caller)
224{
225 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
226 if (trans == NULL) {
227 return NULL;
228 }
229
230 trans->caller = caller;
[0a6fa9f]231 trans->data_caller = 0;
[93f8da1]232 trans->buffer = NULL;
233
234 return trans;
235}
[a76b01b4]236
[8f68913f]237static void callback_out(int outcome, void *arg)
[1b22bd4]238{
[272f46f8]239 async_transaction_t *trans = arg;
[1b22bd4]240
[17aca1c]241 async_answer_0(trans->caller, outcome);
[1b22bd4]242
[93f8da1]243 async_transaction_destroy(trans);
[1b22bd4]244}
[a76b01b4]245
[8f68913f]246static void callback_in(int outcome, size_t actual_size, void *arg)
[1b22bd4]247{
248 async_transaction_t *trans = (async_transaction_t *)arg;
249
[daec5e04]250 if (outcome != EOK) {
[17aca1c]251 async_answer_0(trans->caller, outcome);
[5842493]252 if (trans->data_caller) {
253 async_answer_0(trans->data_caller, EINTR);
254 }
[93f8da1]255 async_transaction_destroy(trans);
256 return;
257 }
[1b22bd4]258
[0a6fa9f]259 if (trans->data_caller) {
260 async_data_read_finalize(trans->data_caller,
261 trans->buffer, actual_size);
262 }
263
[daec5e04]264 async_answer_0(trans->caller, EOK);
[1e64b250]265
266 async_transaction_destroy(trans);
[91db50ac]267}
[a76b01b4]268
[bbce2c2]269void remote_usbhc_read(
[ffe3fe1]270 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
271{
272 assert(fun);
273 assert(iface);
274 assert(call);
275
276 const usbhc_iface_t *hc_iface = iface;
277
278 if (!hc_iface->read) {
279 async_answer_0(callid, ENOTSUP);
280 return;
281 }
282
[365e29e2]283 const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
[bdd8ad2f]284 const uint64_t setup =
285 ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
286 (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
[ffe3fe1]287
288 async_transaction_t *trans = async_transaction_create(callid);
289 if (trans == NULL) {
290 async_answer_0(callid, ENOMEM);
291 return;
292 }
293
[272f46f8]294 size_t size = 0;
295 if (!async_data_read_receive(&trans->data_caller, &size)) {
[ffe3fe1]296 async_answer_0(callid, EPARTY);
297 return;
298 }
299
[272f46f8]300 trans->buffer = malloc(size);
[ffe3fe1]301 if (trans->buffer == NULL) {
302 async_answer_0(trans->data_caller, ENOMEM);
303 async_answer_0(callid, ENOMEM);
304 async_transaction_destroy(trans);
[99172baf]305 return;
[ffe3fe1]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.