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

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

Remove traces of GET_BUFFER method

  • Property mode set to 100644
File size: 16.8 KB
Line 
1/*
2 * Copyright (c) 2010-2011 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 <async.h>
36#include <errno.h>
37
38#include "usbhc_iface.h"
39#include "driver.h"
40
41#define USB_MAX_PAYLOAD_SIZE 1020
42
43static void remote_usbhc_get_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
44static void remote_usbhc_interrupt_out(device_t *, void *, ipc_callid_t, ipc_call_t *);
45static void remote_usbhc_interrupt_in(device_t *, void *, ipc_callid_t, ipc_call_t *);
46static void remote_usbhc_control_write_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
47static void remote_usbhc_control_write_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
48static void remote_usbhc_control_write_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
49static void remote_usbhc_control_read_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
50static void remote_usbhc_control_read_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
51static void remote_usbhc_control_read_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
52static void remote_usbhc_control_write(device_t *, void *, ipc_callid_t, ipc_call_t *);
53static void remote_usbhc_control_read(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 host controller interface operations. */
62static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
63 remote_usbhc_get_address,
64
65 remote_usbhc_reserve_default_address,
66 remote_usbhc_release_default_address,
67
68 remote_usbhc_request_address,
69 remote_usbhc_bind_address,
70 remote_usbhc_release_address,
71
72 remote_usbhc_interrupt_out,
73 remote_usbhc_interrupt_in,
74
75 remote_usbhc_control_write_setup,
76 remote_usbhc_control_write_data,
77 remote_usbhc_control_write_status,
78
79 remote_usbhc_control_read_setup,
80 remote_usbhc_control_read_data,
81 remote_usbhc_control_read_status,
82
83 remote_usbhc_control_write,
84 remote_usbhc_control_read
85};
86
87/** Remote USB host controller interface structure.
88 */
89remote_iface_t remote_usbhc_iface = {
90 .method_count = sizeof(remote_usbhc_iface_ops) /
91 sizeof(remote_usbhc_iface_ops[0]),
92 .methods = remote_usbhc_iface_ops
93};
94
95typedef struct {
96 ipc_callid_t caller;
97 ipc_callid_t data_caller;
98 void *buffer;
99 void *setup_packet;
100 size_t size;
101} async_transaction_t;
102
103static void async_transaction_destroy(async_transaction_t *trans)
104{
105 if (trans == NULL) {
106 return;
107 }
108
109 if (trans->setup_packet != NULL) {
110 free(trans->setup_packet);
111 }
112 if (trans->buffer != NULL) {
113 free(trans->buffer);
114 }
115
116 free(trans);
117}
118
119static async_transaction_t *async_transaction_create(ipc_callid_t caller)
120{
121 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
122 if (trans == NULL) {
123 return NULL;
124 }
125
126 trans->caller = caller;
127 trans->data_caller = 0;
128 trans->buffer = NULL;
129 trans->setup_packet = NULL;
130 trans->size = 0;
131
132 return trans;
133}
134
135void remote_usbhc_get_address(device_t *device, void *iface,
136 ipc_callid_t callid, ipc_call_t *call)
137{
138 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
139
140 if (!usb_iface->tell_address) {
141 async_answer_0(callid, ENOTSUP);
142 return;
143 }
144
145 devman_handle_t handle = DEV_IPC_GET_ARG1(*call);
146
147 usb_address_t address;
148 int rc = usb_iface->tell_address(device, handle, &address);
149 if (rc != EOK) {
150 async_answer_0(callid, rc);
151 } else {
152 async_answer_1(callid, EOK, address);
153 }
154}
155
156void remote_usbhc_reserve_default_address(device_t *device, void *iface,
157 ipc_callid_t callid, ipc_call_t *call)
158{
159 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
160
161 if (!usb_iface->reserve_default_address) {
162 async_answer_0(callid, ENOTSUP);
163 return;
164 }
165
166 int rc = usb_iface->reserve_default_address(device);
167
168 async_answer_0(callid, rc);
169}
170
171void remote_usbhc_release_default_address(device_t *device, void *iface,
172 ipc_callid_t callid, ipc_call_t *call)
173{
174 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
175
176 if (!usb_iface->release_default_address) {
177 async_answer_0(callid, ENOTSUP);
178 return;
179 }
180
181 int rc = usb_iface->release_default_address(device);
182
183 async_answer_0(callid, rc);
184}
185
186void remote_usbhc_request_address(device_t *device, void *iface,
187 ipc_callid_t callid, ipc_call_t *call)
188{
189 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
190
191 if (!usb_iface->request_address) {
192 async_answer_0(callid, ENOTSUP);
193 return;
194 }
195
196 usb_address_t address;
197 int rc = usb_iface->request_address(device, &address);
198 if (rc != EOK) {
199 async_answer_0(callid, rc);
200 } else {
201 async_answer_1(callid, EOK, (sysarg_t) address);
202 }
203}
204
205void remote_usbhc_bind_address(device_t *device, void *iface,
206 ipc_callid_t callid, ipc_call_t *call)
207{
208 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
209
210 if (!usb_iface->bind_address) {
211 async_answer_0(callid, ENOTSUP);
212 return;
213 }
214
215 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
216 devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
217
218 int rc = usb_iface->bind_address(device, address, handle);
219
220 async_answer_0(callid, rc);
221}
222
223void remote_usbhc_release_address(device_t *device, void *iface,
224 ipc_callid_t callid, ipc_call_t *call)
225{
226 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
227
228 if (!usb_iface->release_address) {
229 async_answer_0(callid, ENOTSUP);
230 return;
231 }
232
233 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
234
235 int rc = usb_iface->release_address(device, address);
236
237 async_answer_0(callid, rc);
238}
239
240
241static void callback_out(device_t *device,
242 usb_transaction_outcome_t outcome, void *arg)
243{
244 async_transaction_t *trans = (async_transaction_t *)arg;
245
246 async_answer_0(trans->caller, outcome);
247
248 async_transaction_destroy(trans);
249}
250
251static void callback_in(device_t *device,
252 usb_transaction_outcome_t outcome, size_t actual_size, void *arg)
253{
254 async_transaction_t *trans = (async_transaction_t *)arg;
255
256 if (outcome != USB_OUTCOME_OK) {
257 async_answer_0(trans->caller, outcome);
258 async_transaction_destroy(trans);
259 return;
260 }
261
262 trans->size = actual_size;
263
264 if (trans->data_caller) {
265 async_data_read_finalize(trans->data_caller,
266 trans->buffer, actual_size);
267 }
268
269 async_answer_0(trans->caller, USB_OUTCOME_OK);
270
271 async_transaction_destroy(trans);
272}
273
274/** Process an outgoing transfer (both OUT and SETUP).
275 *
276 * @param device Target device.
277 * @param callid Initiating caller.
278 * @param call Initiating call.
279 * @param transfer_func Transfer function (might be NULL).
280 */
281static void remote_usbhc_out_transfer(device_t *device,
282 ipc_callid_t callid, ipc_call_t *call,
283 usbhc_iface_transfer_out_t transfer_func)
284{
285 if (!transfer_func) {
286 async_answer_0(callid, ENOTSUP);
287 return;
288 }
289
290 size_t expected_len = DEV_IPC_GET_ARG3(*call);
291 usb_target_t target = {
292 .address = DEV_IPC_GET_ARG1(*call),
293 .endpoint = DEV_IPC_GET_ARG2(*call)
294 };
295
296 size_t len = 0;
297 void *buffer = NULL;
298 if (expected_len > 0) {
299 int rc = async_data_write_accept(&buffer, false,
300 1, USB_MAX_PAYLOAD_SIZE,
301 0, &len);
302
303 if (rc != EOK) {
304 async_answer_0(callid, rc);
305 return;
306 }
307 }
308
309 async_transaction_t *trans = async_transaction_create(callid);
310 if (trans == NULL) {
311 if (buffer != NULL) {
312 free(buffer);
313 }
314 async_answer_0(callid, ENOMEM);
315 return;
316 }
317
318 trans->buffer = buffer;
319 trans->size = len;
320
321 int rc = transfer_func(device, target, buffer, len,
322 callback_out, trans);
323
324 if (rc != EOK) {
325 async_answer_0(callid, rc);
326 async_transaction_destroy(trans);
327 }
328}
329
330/** Process an incoming transfer.
331 *
332 * @param device Target device.
333 * @param callid Initiating caller.
334 * @param call Initiating call.
335 * @param transfer_func Transfer function (might be NULL).
336 */
337static void remote_usbhc_in_transfer(device_t *device,
338 ipc_callid_t callid, ipc_call_t *call,
339 usbhc_iface_transfer_in_t transfer_func)
340{
341 if (!transfer_func) {
342 async_answer_0(callid, ENOTSUP);
343 return;
344 }
345
346 size_t len = DEV_IPC_GET_ARG3(*call);
347 usb_target_t target = {
348 .address = DEV_IPC_GET_ARG1(*call),
349 .endpoint = DEV_IPC_GET_ARG2(*call)
350 };
351
352 ipc_callid_t data_callid;
353 if (!async_data_read_receive(&data_callid, &len)) {
354 async_answer_0(callid, EPARTY);
355 return;
356 }
357
358 async_transaction_t *trans = async_transaction_create(callid);
359 if (trans == NULL) {
360 async_answer_0(callid, ENOMEM);
361 return;
362 }
363 trans->data_caller = data_callid;
364 trans->buffer = malloc(len);
365 trans->size = len;
366
367 int rc = transfer_func(device, target, trans->buffer, len,
368 callback_in, trans);
369
370 if (rc != EOK) {
371 async_answer_0(callid, rc);
372 async_transaction_destroy(trans);
373 }
374}
375
376/** Process status part of control transfer.
377 *
378 * @param device Target device.
379 * @param callid Initiating caller.
380 * @param call Initiating call.
381 * @param direction Transfer direction (read ~ in, write ~ out).
382 * @param transfer_in_func Transfer function for control read (might be NULL).
383 * @param transfer_out_func Transfer function for control write (might be NULL).
384 */
385static void remote_usbhc_status_transfer(device_t *device,
386 ipc_callid_t callid, ipc_call_t *call,
387 usb_direction_t direction,
388 int (*transfer_in_func)(device_t *, usb_target_t,
389 usbhc_iface_transfer_in_callback_t, void *),
390 int (*transfer_out_func)(device_t *, usb_target_t,
391 usbhc_iface_transfer_out_callback_t, void *))
392{
393 switch (direction) {
394 case USB_DIRECTION_IN:
395 if (!transfer_in_func) {
396 async_answer_0(callid, ENOTSUP);
397 return;
398 }
399 break;
400 case USB_DIRECTION_OUT:
401 if (!transfer_out_func) {
402 async_answer_0(callid, ENOTSUP);
403 return;
404 }
405 break;
406 default:
407 assert(false && "unreachable code");
408 break;
409 }
410
411 usb_target_t target = {
412 .address = DEV_IPC_GET_ARG1(*call),
413 .endpoint = DEV_IPC_GET_ARG2(*call)
414 };
415
416 async_transaction_t *trans = async_transaction_create(callid);
417 if (trans == NULL) {
418 async_answer_0(callid, ENOMEM);
419 return;
420 }
421
422 int rc;
423 switch (direction) {
424 case USB_DIRECTION_IN:
425 rc = transfer_in_func(device, target,
426 callback_in, trans);
427 break;
428 case USB_DIRECTION_OUT:
429 rc = transfer_out_func(device, target,
430 callback_out, trans);
431 break;
432 default:
433 assert(false && "unreachable code");
434 break;
435 }
436
437 if (rc != EOK) {
438 async_answer_0(callid, rc);
439 async_transaction_destroy(trans);
440 }
441}
442
443
444void remote_usbhc_interrupt_out(device_t *device, void *iface,
445 ipc_callid_t callid, ipc_call_t *call)
446{
447 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
448 assert(usb_iface != NULL);
449
450 return remote_usbhc_out_transfer(device, callid, call,
451 usb_iface->interrupt_out);
452}
453
454void remote_usbhc_interrupt_in(device_t *device, void *iface,
455 ipc_callid_t callid, ipc_call_t *call)
456{
457 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
458 assert(usb_iface != NULL);
459
460 return remote_usbhc_in_transfer(device, callid, call,
461 usb_iface->interrupt_in);
462}
463
464void remote_usbhc_control_write_setup(device_t *device, void *iface,
465 ipc_callid_t callid, ipc_call_t *call)
466{
467 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
468 assert(usb_iface != NULL);
469
470 return remote_usbhc_out_transfer(device, callid, call,
471 usb_iface->control_write_setup);
472}
473
474void remote_usbhc_control_write_data(device_t *device, void *iface,
475 ipc_callid_t callid, ipc_call_t *call)
476{
477 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
478 assert(usb_iface != NULL);
479
480 return remote_usbhc_out_transfer(device, callid, call,
481 usb_iface->control_write_data);
482}
483
484void remote_usbhc_control_write_status(device_t *device, void *iface,
485 ipc_callid_t callid, ipc_call_t *call)
486{
487 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
488 assert(usb_iface != NULL);
489
490 return remote_usbhc_status_transfer(device, callid, call,
491 USB_DIRECTION_IN, usb_iface->control_write_status, NULL);
492}
493
494void remote_usbhc_control_read_setup(device_t *device, void *iface,
495 ipc_callid_t callid, ipc_call_t *call)
496{
497 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
498 assert(usb_iface != NULL);
499
500 return remote_usbhc_out_transfer(device, callid, call,
501 usb_iface->control_read_setup);
502}
503
504void remote_usbhc_control_read_data(device_t *device, void *iface,
505 ipc_callid_t callid, ipc_call_t *call)
506{
507 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
508 assert(usb_iface != NULL);
509
510 return remote_usbhc_in_transfer(device, callid, call,
511 usb_iface->control_read_data);
512}
513
514void remote_usbhc_control_read_status(device_t *device, void *iface,
515 ipc_callid_t callid, ipc_call_t *call)
516{
517 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
518 assert(usb_iface != NULL);
519
520 return remote_usbhc_status_transfer(device, callid, call,
521 USB_DIRECTION_OUT, NULL, usb_iface->control_read_status);
522}
523
524void remote_usbhc_control_write(device_t *device, void *iface,
525ipc_callid_t callid, ipc_call_t *call)
526{
527 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
528 assert(usb_iface != NULL);
529
530 if (!usb_iface->control_write) {
531 async_answer_0(callid, ENOTSUP);
532 return;
533 }
534
535 usb_target_t target = {
536 .address = DEV_IPC_GET_ARG1(*call),
537 .endpoint = DEV_IPC_GET_ARG2(*call)
538 };
539
540 int rc;
541
542 void *setup_packet = NULL;
543 void *data_buffer = NULL;
544 size_t setup_packet_len = 0;
545 size_t data_buffer_len = 0;
546
547 rc = async_data_write_accept(&setup_packet, false,
548 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
549 if (rc != EOK) {
550 async_answer_0(callid, rc);
551 return;
552 }
553 rc = async_data_write_accept(&data_buffer, false,
554 1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
555 if (rc != EOK) {
556 async_answer_0(callid, rc);
557 free(setup_packet);
558 return;
559 }
560
561 async_transaction_t *trans = async_transaction_create(callid);
562 if (trans == NULL) {
563 async_answer_0(callid, ENOMEM);
564 free(setup_packet);
565 free(data_buffer);
566 return;
567 }
568 trans->setup_packet = setup_packet;
569 trans->buffer = data_buffer;
570 trans->size = data_buffer_len;
571
572 rc = usb_iface->control_write(device, target,
573 setup_packet, setup_packet_len,
574 data_buffer, data_buffer_len,
575 callback_out, trans);
576
577 if (rc != EOK) {
578 async_answer_0(callid, rc);
579 async_transaction_destroy(trans);
580 }
581}
582
583
584void remote_usbhc_control_read(device_t *device, void *iface,
585ipc_callid_t callid, ipc_call_t *call)
586{
587 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
588 assert(usb_iface != NULL);
589
590 if (!usb_iface->control_read) {
591 async_answer_0(callid, ENOTSUP);
592 return;
593 }
594
595 size_t data_len = DEV_IPC_GET_ARG3(*call);
596 usb_target_t target = {
597 .address = DEV_IPC_GET_ARG1(*call),
598 .endpoint = DEV_IPC_GET_ARG2(*call)
599 };
600
601 int rc;
602
603 void *setup_packet = NULL;
604 size_t setup_packet_len = 0;
605
606 rc = async_data_write_accept(&setup_packet, false,
607 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
608 if (rc != EOK) {
609 async_answer_0(callid, rc);
610 return;
611 }
612
613 ipc_callid_t data_callid;
614 if (!async_data_read_receive(&data_callid, &data_len)) {
615 async_answer_0(callid, EPARTY);
616 free(setup_packet);
617 return;
618 }
619
620 async_transaction_t *trans = async_transaction_create(callid);
621 if (trans == NULL) {
622 async_answer_0(callid, ENOMEM);
623 free(setup_packet);
624 return;
625 }
626 trans->data_caller = data_callid;
627 trans->setup_packet = setup_packet;
628 trans->size = data_len;
629 trans->buffer = malloc(data_len);
630 if (trans->buffer == NULL) {
631 async_answer_0(callid, ENOMEM);
632 async_transaction_destroy(trans);
633 return;
634 }
635
636 rc = usb_iface->control_read(device, target,
637 setup_packet, setup_packet_len,
638 trans->buffer, trans->size,
639 callback_in, trans);
640
641 if (rc != EOK) {
642 async_answer_0(callid, rc);
643 async_transaction_destroy(trans);
644 }
645}
646
647
648
649/**
650 * @}
651 */
Note: See TracBrowser for help on using the repository browser.