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

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

Refactoring of remote USBHC interface

It is still not optimal but at least less error prone.

  • Property mode set to 100644
File size: 10.9 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 libdrv
30 * @{
31 */
32/** @file
33 */
34
35#include <ipc/ipc.h>
36#include <async.h>
37#include <errno.h>
38
39#include "usbhc_iface.h"
40#include "driver.h"
41
42#define USB_MAX_PAYLOAD_SIZE 1020
43
44static void remote_usbhc_get_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
45static void remote_usbhc_get_buffer(device_t *, void *, ipc_callid_t, ipc_call_t *);
46static void remote_usbhc_interrupt_out(device_t *, void *, ipc_callid_t, ipc_call_t *);
47static void remote_usbhc_interrupt_in(device_t *, void *, ipc_callid_t, ipc_call_t *);
48static void remote_usbhc_control_write_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
49static void remote_usbhc_control_write_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
50static void remote_usbhc_control_write_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
51static void remote_usbhc_control_read_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
52static void remote_usbhc_control_read_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
53static void remote_usbhc_control_read_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
54//static void remote_usbhc(device_t *, void *, ipc_callid_t, ipc_call_t *);
55
56/** Remote USB interface operations. */
57static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
58 remote_usbhc_get_address,
59 remote_usbhc_get_buffer,
60 remote_usbhc_interrupt_out,
61 remote_usbhc_interrupt_in,
62 remote_usbhc_control_write_setup,
63 remote_usbhc_control_write_data,
64 remote_usbhc_control_write_status,
65 remote_usbhc_control_read_setup,
66 remote_usbhc_control_read_data,
67 remote_usbhc_control_read_status
68};
69
70/** Remote USB interface structure.
71 */
72remote_iface_t remote_usbhc_iface = {
73 .method_count = sizeof(remote_usbhc_iface_ops) /
74 sizeof(remote_usbhc_iface_ops[0]),
75 .methods = remote_usbhc_iface_ops
76};
77
78typedef struct {
79 ipc_callid_t caller;
80 void *buffer;
81 size_t size;
82} async_transaction_t;
83
84void remote_usbhc_get_address(device_t *device, void *iface,
85 ipc_callid_t callid, ipc_call_t *call)
86{
87 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
88
89 if (!usb_iface->tell_address) {
90 ipc_answer_0(callid, ENOTSUP);
91 return;
92 }
93
94 devman_handle_t handle = IPC_GET_ARG1(*call);
95
96 usb_address_t address;
97 int rc = usb_iface->tell_address(device, handle, &address);
98 if (rc != EOK) {
99 ipc_answer_0(callid, rc);
100 } else {
101 ipc_answer_1(callid, EOK, address);
102 }
103}
104
105void remote_usbhc_get_buffer(device_t *device, void *iface,
106 ipc_callid_t callid, ipc_call_t *call)
107{
108 ipcarg_t buffer_hash = IPC_GET_ARG1(*call);
109 async_transaction_t * trans = (async_transaction_t *)buffer_hash;
110 if (trans == NULL) {
111 ipc_answer_0(callid, ENOENT);
112 return;
113 }
114 if (trans->buffer == NULL) {
115 ipc_answer_0(callid, EINVAL);
116 free(trans);
117 return;
118 }
119
120 ipc_callid_t cid;
121 size_t accepted_size;
122 if (!async_data_read_receive(&cid, &accepted_size)) {
123 ipc_answer_0(callid, EINVAL);
124 return;
125 }
126
127 if (accepted_size > trans->size) {
128 accepted_size = trans->size;
129 }
130 async_data_read_finalize(callid, trans->buffer, accepted_size);
131
132 ipc_answer_1(callid, EOK, accepted_size);
133
134 free(trans->buffer);
135 free(trans);
136}
137
138
139static void callback_out(device_t *device,
140 usb_transaction_outcome_t outcome, void *arg)
141{
142 async_transaction_t *trans = (async_transaction_t *)arg;
143
144 // FIXME - answer according to outcome
145 ipc_answer_0(trans->caller, EOK);
146
147 free(trans);
148}
149
150static void callback_in(device_t *device,
151 usb_transaction_outcome_t outcome, size_t actual_size, void *arg)
152{
153 async_transaction_t *trans = (async_transaction_t *)arg;
154
155 // FIXME - answer according to outcome
156 ipc_answer_1(trans->caller, EOK, (ipcarg_t)trans);
157
158 trans->size = actual_size;
159}
160
161/** Process an outgoing transfer (both OUT and SETUP).
162 *
163 * @param device Target device.
164 * @param callid Initiating caller.
165 * @param call Initiating call.
166 * @param transfer_func Transfer function (might be NULL).
167 */
168static void remote_usbhc_out_transfer(device_t *device,
169 ipc_callid_t callid, ipc_call_t *call,
170 usbhc_iface_transfer_out_t transfer_func)
171{
172 if (!transfer_func) {
173 ipc_answer_0(callid, ENOTSUP);
174 return;
175 }
176
177 size_t expected_len = IPC_GET_ARG3(*call);
178 usb_target_t target = {
179 .address = IPC_GET_ARG1(*call),
180 .endpoint = IPC_GET_ARG2(*call)
181 };
182
183 size_t len = 0;
184 void *buffer = NULL;
185 if (expected_len > 0) {
186 int rc = async_data_write_accept(&buffer, false,
187 1, USB_MAX_PAYLOAD_SIZE,
188 0, &len);
189
190 if (rc != EOK) {
191 ipc_answer_0(callid, rc);
192 return;
193 }
194 }
195
196 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
197 trans->caller = callid;
198 trans->buffer = buffer;
199 trans->size = len;
200
201 int rc = transfer_func(device, target, buffer, len,
202 callback_out, trans);
203
204 if (rc != EOK) {
205 ipc_answer_0(callid, rc);
206 if (buffer != NULL) {
207 free(buffer);
208 }
209 free(trans);
210 }
211}
212
213/** Process an incoming transfer.
214 *
215 * @param device Target device.
216 * @param callid Initiating caller.
217 * @param call Initiating call.
218 * @param transfer_func Transfer function (might be NULL).
219 */
220static void remote_usbhc_in_transfer(device_t *device,
221 ipc_callid_t callid, ipc_call_t *call,
222 usbhc_iface_transfer_in_t transfer_func)
223{
224 if (!transfer_func) {
225 ipc_answer_0(callid, ENOTSUP);
226 return;
227 }
228
229 size_t len = IPC_GET_ARG3(*call);
230 usb_target_t target = {
231 .address = IPC_GET_ARG1(*call),
232 .endpoint = IPC_GET_ARG2(*call)
233 };
234
235 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
236 trans->caller = callid;
237 trans->buffer = malloc(len);
238 trans->size = len;
239
240 int rc = transfer_func(device, target, trans->buffer, len,
241 callback_in, trans);
242
243 if (rc != EOK) {
244 ipc_answer_0(callid, rc);
245 free(trans->buffer);
246 free(trans);
247 }
248}
249
250/** Process status part of control transfer.
251 *
252 * @param device Target device.
253 * @param callid Initiating caller.
254 * @param call Initiating call.
255 * @param direction Transfer direction (read ~ in, write ~ out).
256 * @param transfer_in_func Transfer function for control read (might be NULL).
257 * @param transfer_out_func Transfer function for control write (might be NULL).
258 */
259static void remote_usbhc_status_transfer(device_t *device,
260 ipc_callid_t callid, ipc_call_t *call,
261 usb_direction_t direction,
262 int (*transfer_in_func)(device_t *, usb_target_t,
263 usbhc_iface_transfer_in_callback_t, void *),
264 int (*transfer_out_func)(device_t *, usb_target_t,
265 usbhc_iface_transfer_out_callback_t, void *))
266{
267 switch (direction) {
268 case USB_DIRECTION_IN:
269 if (!transfer_in_func) {
270 ipc_answer_0(callid, ENOTSUP);
271 return;
272 }
273 break;
274 case USB_DIRECTION_OUT:
275 if (!transfer_out_func) {
276 ipc_answer_0(callid, ENOTSUP);
277 return;
278 }
279 break;
280 default:
281 assert(false && "unreachable code");
282 break;
283 }
284
285 usb_target_t target = {
286 .address = IPC_GET_ARG1(*call),
287 .endpoint = IPC_GET_ARG2(*call)
288 };
289
290 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
291 trans->caller = callid;
292 trans->buffer = NULL;
293 trans->size = 0;
294
295 int rc;
296 switch (direction) {
297 case USB_DIRECTION_IN:
298 rc = transfer_in_func(device, target,
299 callback_in, trans);
300 break;
301 case USB_DIRECTION_OUT:
302 rc = transfer_out_func(device, target,
303 callback_out, trans);
304 break;
305 default:
306 assert(false && "unreachable code");
307 break;
308 }
309
310 if (rc != EOK) {
311 ipc_answer_0(callid, rc);
312 free(trans);
313 }
314 return;
315}
316
317
318void remote_usbhc_interrupt_out(device_t *device, void *iface,
319 ipc_callid_t callid, ipc_call_t *call)
320{
321 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
322 assert(usb_iface != NULL);
323
324 return remote_usbhc_out_transfer(device, callid, call,
325 usb_iface->interrupt_out);
326}
327
328void remote_usbhc_interrupt_in(device_t *device, void *iface,
329 ipc_callid_t callid, ipc_call_t *call)
330{
331 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
332 assert(usb_iface != NULL);
333
334 return remote_usbhc_in_transfer(device, callid, call,
335 usb_iface->interrupt_in);
336}
337
338void remote_usbhc_control_write_setup(device_t *device, void *iface,
339 ipc_callid_t callid, ipc_call_t *call)
340{
341 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
342 assert(usb_iface != NULL);
343
344 return remote_usbhc_out_transfer(device, callid, call,
345 usb_iface->control_write_setup);
346}
347
348void remote_usbhc_control_write_data(device_t *device, void *iface,
349 ipc_callid_t callid, ipc_call_t *call)
350{
351 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
352 assert(usb_iface != NULL);
353
354 return remote_usbhc_out_transfer(device, callid, call,
355 usb_iface->control_write_data);
356}
357
358void remote_usbhc_control_write_status(device_t *device, void *iface,
359 ipc_callid_t callid, ipc_call_t *call)
360{
361 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
362 assert(usb_iface != NULL);
363
364 return remote_usbhc_status_transfer(device, callid, call,
365 USB_DIRECTION_IN, usb_iface->control_write_status, NULL);
366}
367
368void remote_usbhc_control_read_setup(device_t *device, void *iface,
369 ipc_callid_t callid, ipc_call_t *call)
370{
371 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
372 assert(usb_iface != NULL);
373
374 return remote_usbhc_out_transfer(device, callid, call,
375 usb_iface->control_read_setup);
376}
377
378void remote_usbhc_control_read_data(device_t *device, void *iface,
379 ipc_callid_t callid, ipc_call_t *call)
380{
381 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
382 assert(usb_iface != NULL);
383
384 return remote_usbhc_in_transfer(device, callid, call,
385 usb_iface->control_read_data);
386}
387
388void remote_usbhc_control_read_status(device_t *device, void *iface,
389 ipc_callid_t callid, ipc_call_t *call)
390{
391 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
392 assert(usb_iface != NULL);
393
394 return remote_usbhc_status_transfer(device, callid, call,
395 USB_DIRECTION_OUT, NULL, usb_iface->control_read_status);
396}
397
398
399
400/**
401 * @}
402 */
Note: See TracBrowser for help on using the repository browser.