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

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

Add binding of USB address and devman handle to usbhc iface

  • Property mode set to 100644
File size: 13.5 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 *);
54static void remote_usbhc_reserve_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
55static void remote_usbhc_release_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
56static void remote_usbhc_request_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
57static void remote_usbhc_bind_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
58static void remote_usbhc_release_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
59//static void remote_usbhc(device_t *, void *, ipc_callid_t, ipc_call_t *);
60
61/** Remote USB interface operations. */
62static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
63 remote_usbhc_get_address,
64
65 remote_usbhc_get_buffer,
66
67 remote_usbhc_reserve_default_address,
68 remote_usbhc_release_default_address,
69
70 remote_usbhc_request_address,
71 remote_usbhc_bind_address,
72 remote_usbhc_release_address,
73
74 remote_usbhc_interrupt_out,
75 remote_usbhc_interrupt_in,
76
77 remote_usbhc_control_write_setup,
78 remote_usbhc_control_write_data,
79 remote_usbhc_control_write_status,
80
81 remote_usbhc_control_read_setup,
82 remote_usbhc_control_read_data,
83 remote_usbhc_control_read_status
84};
85
86/** Remote USB interface structure.
87 */
88remote_iface_t remote_usbhc_iface = {
89 .method_count = sizeof(remote_usbhc_iface_ops) /
90 sizeof(remote_usbhc_iface_ops[0]),
91 .methods = remote_usbhc_iface_ops
92};
93
94typedef struct {
95 ipc_callid_t caller;
96 void *buffer;
97 size_t size;
98} async_transaction_t;
99
100void remote_usbhc_get_address(device_t *device, void *iface,
101 ipc_callid_t callid, ipc_call_t *call)
102{
103 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
104
105 if (!usb_iface->tell_address) {
106 ipc_answer_0(callid, ENOTSUP);
107 return;
108 }
109
110 devman_handle_t handle = IPC_GET_ARG1(*call);
111
112 usb_address_t address;
113 int rc = usb_iface->tell_address(device, handle, &address);
114 if (rc != EOK) {
115 ipc_answer_0(callid, rc);
116 } else {
117 ipc_answer_1(callid, EOK, address);
118 }
119}
120
121void remote_usbhc_get_buffer(device_t *device, void *iface,
122 ipc_callid_t callid, ipc_call_t *call)
123{
124 ipcarg_t buffer_hash = IPC_GET_ARG1(*call);
125 async_transaction_t * trans = (async_transaction_t *)buffer_hash;
126 if (trans == NULL) {
127 ipc_answer_0(callid, ENOENT);
128 return;
129 }
130 if (trans->buffer == NULL) {
131 ipc_answer_0(callid, EINVAL);
132 free(trans);
133 return;
134 }
135
136 ipc_callid_t cid;
137 size_t accepted_size;
138 if (!async_data_read_receive(&cid, &accepted_size)) {
139 ipc_answer_0(callid, EINVAL);
140 return;
141 }
142
143 if (accepted_size > trans->size) {
144 accepted_size = trans->size;
145 }
146 async_data_read_finalize(callid, trans->buffer, accepted_size);
147
148 ipc_answer_1(callid, EOK, accepted_size);
149
150 free(trans->buffer);
151 free(trans);
152}
153
154void remote_usbhc_reserve_default_address(device_t *device, void *iface,
155 ipc_callid_t callid, ipc_call_t *call)
156{
157 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
158
159 if (!usb_iface->reserve_default_address) {
160 ipc_answer_0(callid, ENOTSUP);
161 return;
162 }
163
164 int rc = usb_iface->reserve_default_address(device);
165
166 ipc_answer_0(callid, rc);
167}
168
169void remote_usbhc_release_default_address(device_t *device, void *iface,
170 ipc_callid_t callid, ipc_call_t *call)
171{
172 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
173
174 if (!usb_iface->release_default_address) {
175 ipc_answer_0(callid, ENOTSUP);
176 return;
177 }
178
179 int rc = usb_iface->release_default_address(device);
180
181 ipc_answer_0(callid, rc);
182}
183
184void remote_usbhc_request_address(device_t *device, void *iface,
185 ipc_callid_t callid, ipc_call_t *call)
186{
187 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
188
189 if (!usb_iface->request_address) {
190 ipc_answer_0(callid, ENOTSUP);
191 return;
192 }
193
194 usb_address_t address;
195 int rc = usb_iface->request_address(device, &address);
196 if (rc != EOK) {
197 ipc_answer_0(callid, rc);
198 } else {
199 ipc_answer_1(callid, EOK, (ipcarg_t) address);
200 }
201}
202
203void remote_usbhc_bind_address(device_t *device, void *iface,
204 ipc_callid_t callid, ipc_call_t *call)
205{
206 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
207
208 if (!usb_iface->bind_address) {
209 ipc_answer_0(callid, ENOTSUP);
210 return;
211 }
212
213 usb_address_t address = (usb_address_t) IPC_GET_ARG1(*call);
214 devman_handle_t handle = (devman_handle_t) IPC_GET_ARG2(*call);
215
216 int rc = usb_iface->bind_address(device, address, handle);
217
218 ipc_answer_0(callid, rc);
219}
220
221void remote_usbhc_release_address(device_t *device, void *iface,
222 ipc_callid_t callid, ipc_call_t *call)
223{
224 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
225
226 if (!usb_iface->release_address) {
227 ipc_answer_0(callid, ENOTSUP);
228 return;
229 }
230
231 usb_address_t address = (usb_address_t) IPC_GET_ARG1(*call);
232
233 int rc = usb_iface->release_address(device, address);
234
235 ipc_answer_0(callid, rc);
236}
237
238
239static void callback_out(device_t *device,
240 usb_transaction_outcome_t outcome, void *arg)
241{
242 async_transaction_t *trans = (async_transaction_t *)arg;
243
244 // FIXME - answer according to outcome
245 ipc_answer_0(trans->caller, EOK);
246
247 free(trans);
248}
249
250static void callback_in(device_t *device,
251 usb_transaction_outcome_t outcome, size_t actual_size, void *arg)
252{
253 async_transaction_t *trans = (async_transaction_t *)arg;
254
255 // FIXME - answer according to outcome
256 ipc_answer_1(trans->caller, EOK, (ipcarg_t)trans);
257
258 trans->size = actual_size;
259}
260
261/** Process an outgoing transfer (both OUT and SETUP).
262 *
263 * @param device Target device.
264 * @param callid Initiating caller.
265 * @param call Initiating call.
266 * @param transfer_func Transfer function (might be NULL).
267 */
268static void remote_usbhc_out_transfer(device_t *device,
269 ipc_callid_t callid, ipc_call_t *call,
270 usbhc_iface_transfer_out_t transfer_func)
271{
272 if (!transfer_func) {
273 ipc_answer_0(callid, ENOTSUP);
274 return;
275 }
276
277 size_t expected_len = IPC_GET_ARG3(*call);
278 usb_target_t target = {
279 .address = IPC_GET_ARG1(*call),
280 .endpoint = IPC_GET_ARG2(*call)
281 };
282
283 size_t len = 0;
284 void *buffer = NULL;
285 if (expected_len > 0) {
286 int rc = async_data_write_accept(&buffer, false,
287 1, USB_MAX_PAYLOAD_SIZE,
288 0, &len);
289
290 if (rc != EOK) {
291 ipc_answer_0(callid, rc);
292 return;
293 }
294 }
295
296 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
297 trans->caller = callid;
298 trans->buffer = buffer;
299 trans->size = len;
300
301 int rc = transfer_func(device, target, buffer, len,
302 callback_out, trans);
303
304 if (rc != EOK) {
305 ipc_answer_0(callid, rc);
306 if (buffer != NULL) {
307 free(buffer);
308 }
309 free(trans);
310 }
311}
312
313/** Process an incoming transfer.
314 *
315 * @param device Target device.
316 * @param callid Initiating caller.
317 * @param call Initiating call.
318 * @param transfer_func Transfer function (might be NULL).
319 */
320static void remote_usbhc_in_transfer(device_t *device,
321 ipc_callid_t callid, ipc_call_t *call,
322 usbhc_iface_transfer_in_t transfer_func)
323{
324 if (!transfer_func) {
325 ipc_answer_0(callid, ENOTSUP);
326 return;
327 }
328
329 size_t len = IPC_GET_ARG3(*call);
330 usb_target_t target = {
331 .address = IPC_GET_ARG1(*call),
332 .endpoint = IPC_GET_ARG2(*call)
333 };
334
335 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
336 trans->caller = callid;
337 trans->buffer = malloc(len);
338 trans->size = len;
339
340 int rc = transfer_func(device, target, trans->buffer, len,
341 callback_in, trans);
342
343 if (rc != EOK) {
344 ipc_answer_0(callid, rc);
345 free(trans->buffer);
346 free(trans);
347 }
348}
349
350/** Process status part of control transfer.
351 *
352 * @param device Target device.
353 * @param callid Initiating caller.
354 * @param call Initiating call.
355 * @param direction Transfer direction (read ~ in, write ~ out).
356 * @param transfer_in_func Transfer function for control read (might be NULL).
357 * @param transfer_out_func Transfer function for control write (might be NULL).
358 */
359static void remote_usbhc_status_transfer(device_t *device,
360 ipc_callid_t callid, ipc_call_t *call,
361 usb_direction_t direction,
362 int (*transfer_in_func)(device_t *, usb_target_t,
363 usbhc_iface_transfer_in_callback_t, void *),
364 int (*transfer_out_func)(device_t *, usb_target_t,
365 usbhc_iface_transfer_out_callback_t, void *))
366{
367 switch (direction) {
368 case USB_DIRECTION_IN:
369 if (!transfer_in_func) {
370 ipc_answer_0(callid, ENOTSUP);
371 return;
372 }
373 break;
374 case USB_DIRECTION_OUT:
375 if (!transfer_out_func) {
376 ipc_answer_0(callid, ENOTSUP);
377 return;
378 }
379 break;
380 default:
381 assert(false && "unreachable code");
382 break;
383 }
384
385 usb_target_t target = {
386 .address = IPC_GET_ARG1(*call),
387 .endpoint = IPC_GET_ARG2(*call)
388 };
389
390 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
391 trans->caller = callid;
392 trans->buffer = NULL;
393 trans->size = 0;
394
395 int rc;
396 switch (direction) {
397 case USB_DIRECTION_IN:
398 rc = transfer_in_func(device, target,
399 callback_in, trans);
400 break;
401 case USB_DIRECTION_OUT:
402 rc = transfer_out_func(device, target,
403 callback_out, trans);
404 break;
405 default:
406 assert(false && "unreachable code");
407 break;
408 }
409
410 if (rc != EOK) {
411 ipc_answer_0(callid, rc);
412 free(trans);
413 }
414 return;
415}
416
417
418void remote_usbhc_interrupt_out(device_t *device, void *iface,
419 ipc_callid_t callid, ipc_call_t *call)
420{
421 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
422 assert(usb_iface != NULL);
423
424 return remote_usbhc_out_transfer(device, callid, call,
425 usb_iface->interrupt_out);
426}
427
428void remote_usbhc_interrupt_in(device_t *device, void *iface,
429 ipc_callid_t callid, ipc_call_t *call)
430{
431 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
432 assert(usb_iface != NULL);
433
434 return remote_usbhc_in_transfer(device, callid, call,
435 usb_iface->interrupt_in);
436}
437
438void remote_usbhc_control_write_setup(device_t *device, void *iface,
439 ipc_callid_t callid, ipc_call_t *call)
440{
441 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
442 assert(usb_iface != NULL);
443
444 return remote_usbhc_out_transfer(device, callid, call,
445 usb_iface->control_write_setup);
446}
447
448void remote_usbhc_control_write_data(device_t *device, void *iface,
449 ipc_callid_t callid, ipc_call_t *call)
450{
451 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
452 assert(usb_iface != NULL);
453
454 return remote_usbhc_out_transfer(device, callid, call,
455 usb_iface->control_write_data);
456}
457
458void remote_usbhc_control_write_status(device_t *device, void *iface,
459 ipc_callid_t callid, ipc_call_t *call)
460{
461 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
462 assert(usb_iface != NULL);
463
464 return remote_usbhc_status_transfer(device, callid, call,
465 USB_DIRECTION_IN, usb_iface->control_write_status, NULL);
466}
467
468void remote_usbhc_control_read_setup(device_t *device, void *iface,
469 ipc_callid_t callid, ipc_call_t *call)
470{
471 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
472 assert(usb_iface != NULL);
473
474 return remote_usbhc_out_transfer(device, callid, call,
475 usb_iface->control_read_setup);
476}
477
478void remote_usbhc_control_read_data(device_t *device, void *iface,
479 ipc_callid_t callid, ipc_call_t *call)
480{
481 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
482 assert(usb_iface != NULL);
483
484 return remote_usbhc_in_transfer(device, callid, call,
485 usb_iface->control_read_data);
486}
487
488void remote_usbhc_control_read_status(device_t *device, void *iface,
489 ipc_callid_t callid, ipc_call_t *call)
490{
491 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
492 assert(usb_iface != NULL);
493
494 return remote_usbhc_status_transfer(device, callid, call,
495 USB_DIRECTION_OUT, NULL, usb_iface->control_read_status);
496}
497
498
499
500/**
501 * @}
502 */
Note: See TracBrowser for help on using the repository browser.