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

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

Hack for setting low speed/high speed

Currently, it is only a boolean. Will improve later.

  • Property mode set to 100644
File size: 17.0 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 bool full_speed = DEV_IPC_GET_ARG1(*call);
167
168 int rc = usb_iface->reserve_default_address(device, full_speed);
169
170 async_answer_0(callid, rc);
171}
172
173void remote_usbhc_release_default_address(device_t *device, void *iface,
174 ipc_callid_t callid, ipc_call_t *call)
175{
176 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
177
178 if (!usb_iface->release_default_address) {
179 async_answer_0(callid, ENOTSUP);
180 return;
181 }
182
183 int rc = usb_iface->release_default_address(device);
184
185 async_answer_0(callid, rc);
186}
187
188void remote_usbhc_request_address(device_t *device, void *iface,
189 ipc_callid_t callid, ipc_call_t *call)
190{
191 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
192
193 if (!usb_iface->request_address) {
194 async_answer_0(callid, ENOTSUP);
195 return;
196 }
197
198 bool full_speed = DEV_IPC_GET_ARG1(*call);
199
200 usb_address_t address;
201 int rc = usb_iface->request_address(device, full_speed, &address);
202 if (rc != EOK) {
203 async_answer_0(callid, rc);
204 } else {
205 async_answer_1(callid, EOK, (sysarg_t) address);
206 }
207}
208
209void remote_usbhc_bind_address(device_t *device, void *iface,
210 ipc_callid_t callid, ipc_call_t *call)
211{
212 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
213
214 if (!usb_iface->bind_address) {
215 async_answer_0(callid, ENOTSUP);
216 return;
217 }
218
219 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
220 devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
221
222 int rc = usb_iface->bind_address(device, address, handle);
223
224 async_answer_0(callid, rc);
225}
226
227void remote_usbhc_release_address(device_t *device, void *iface,
228 ipc_callid_t callid, ipc_call_t *call)
229{
230 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
231
232 if (!usb_iface->release_address) {
233 async_answer_0(callid, ENOTSUP);
234 return;
235 }
236
237 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
238
239 int rc = usb_iface->release_address(device, address);
240
241 async_answer_0(callid, rc);
242}
243
244
245static void callback_out(device_t *device,
246 int outcome, void *arg)
247{
248 async_transaction_t *trans = (async_transaction_t *)arg;
249
250 async_answer_0(trans->caller, outcome);
251
252 async_transaction_destroy(trans);
253}
254
255static void callback_in(device_t *device,
256 int outcome, size_t actual_size, void *arg)
257{
258 async_transaction_t *trans = (async_transaction_t *)arg;
259
260 if (outcome != EOK) {
261 async_answer_0(trans->caller, outcome);
262 if (trans->data_caller) {
263 async_answer_0(trans->data_caller, EINTR);
264 }
265 async_transaction_destroy(trans);
266 return;
267 }
268
269 trans->size = actual_size;
270
271 if (trans->data_caller) {
272 async_data_read_finalize(trans->data_caller,
273 trans->buffer, actual_size);
274 }
275
276 async_answer_0(trans->caller, EOK);
277
278 async_transaction_destroy(trans);
279}
280
281/** Process an outgoing transfer (both OUT and SETUP).
282 *
283 * @param device Target device.
284 * @param callid Initiating caller.
285 * @param call Initiating call.
286 * @param transfer_func Transfer function (might be NULL).
287 */
288static void remote_usbhc_out_transfer(device_t *device,
289 ipc_callid_t callid, ipc_call_t *call,
290 usbhc_iface_transfer_out_t transfer_func)
291{
292 if (!transfer_func) {
293 async_answer_0(callid, ENOTSUP);
294 return;
295 }
296
297 size_t expected_len = DEV_IPC_GET_ARG3(*call);
298 usb_target_t target = {
299 .address = DEV_IPC_GET_ARG1(*call),
300 .endpoint = DEV_IPC_GET_ARG2(*call)
301 };
302
303 size_t len = 0;
304 void *buffer = NULL;
305 if (expected_len > 0) {
306 int rc = async_data_write_accept(&buffer, false,
307 1, USB_MAX_PAYLOAD_SIZE,
308 0, &len);
309
310 if (rc != EOK) {
311 async_answer_0(callid, rc);
312 return;
313 }
314 }
315
316 async_transaction_t *trans = async_transaction_create(callid);
317 if (trans == NULL) {
318 if (buffer != NULL) {
319 free(buffer);
320 }
321 async_answer_0(callid, ENOMEM);
322 return;
323 }
324
325 trans->buffer = buffer;
326 trans->size = len;
327
328 int rc = transfer_func(device, target, buffer, len,
329 callback_out, trans);
330
331 if (rc != EOK) {
332 async_answer_0(callid, rc);
333 async_transaction_destroy(trans);
334 }
335}
336
337/** Process an incoming transfer.
338 *
339 * @param device Target device.
340 * @param callid Initiating caller.
341 * @param call Initiating call.
342 * @param transfer_func Transfer function (might be NULL).
343 */
344static void remote_usbhc_in_transfer(device_t *device,
345 ipc_callid_t callid, ipc_call_t *call,
346 usbhc_iface_transfer_in_t transfer_func)
347{
348 if (!transfer_func) {
349 async_answer_0(callid, ENOTSUP);
350 return;
351 }
352
353 size_t len = DEV_IPC_GET_ARG3(*call);
354 usb_target_t target = {
355 .address = DEV_IPC_GET_ARG1(*call),
356 .endpoint = DEV_IPC_GET_ARG2(*call)
357 };
358
359 ipc_callid_t data_callid;
360 if (!async_data_read_receive(&data_callid, &len)) {
361 async_answer_0(callid, EPARTY);
362 return;
363 }
364
365 async_transaction_t *trans = async_transaction_create(callid);
366 if (trans == NULL) {
367 async_answer_0(callid, ENOMEM);
368 return;
369 }
370 trans->data_caller = data_callid;
371 trans->buffer = malloc(len);
372 trans->size = len;
373
374 int rc = transfer_func(device, target, trans->buffer, len,
375 callback_in, trans);
376
377 if (rc != EOK) {
378 async_answer_0(callid, rc);
379 async_transaction_destroy(trans);
380 }
381}
382
383/** Process status part of control transfer.
384 *
385 * @param device Target device.
386 * @param callid Initiating caller.
387 * @param call Initiating call.
388 * @param direction Transfer direction (read ~ in, write ~ out).
389 * @param transfer_in_func Transfer function for control read (might be NULL).
390 * @param transfer_out_func Transfer function for control write (might be NULL).
391 */
392static void remote_usbhc_status_transfer(device_t *device,
393 ipc_callid_t callid, ipc_call_t *call,
394 usb_direction_t direction,
395 int (*transfer_in_func)(device_t *, usb_target_t,
396 usbhc_iface_transfer_in_callback_t, void *),
397 int (*transfer_out_func)(device_t *, usb_target_t,
398 usbhc_iface_transfer_out_callback_t, void *))
399{
400 switch (direction) {
401 case USB_DIRECTION_IN:
402 if (!transfer_in_func) {
403 async_answer_0(callid, ENOTSUP);
404 return;
405 }
406 break;
407 case USB_DIRECTION_OUT:
408 if (!transfer_out_func) {
409 async_answer_0(callid, ENOTSUP);
410 return;
411 }
412 break;
413 default:
414 assert(false && "unreachable code");
415 break;
416 }
417
418 usb_target_t target = {
419 .address = DEV_IPC_GET_ARG1(*call),
420 .endpoint = DEV_IPC_GET_ARG2(*call)
421 };
422
423 async_transaction_t *trans = async_transaction_create(callid);
424 if (trans == NULL) {
425 async_answer_0(callid, ENOMEM);
426 return;
427 }
428
429 int rc;
430 switch (direction) {
431 case USB_DIRECTION_IN:
432 rc = transfer_in_func(device, target,
433 callback_in, trans);
434 break;
435 case USB_DIRECTION_OUT:
436 rc = transfer_out_func(device, target,
437 callback_out, trans);
438 break;
439 default:
440 assert(false && "unreachable code");
441 break;
442 }
443
444 if (rc != EOK) {
445 async_answer_0(callid, rc);
446 async_transaction_destroy(trans);
447 }
448}
449
450
451void remote_usbhc_interrupt_out(device_t *device, void *iface,
452 ipc_callid_t callid, ipc_call_t *call)
453{
454 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
455 assert(usb_iface != NULL);
456
457 return remote_usbhc_out_transfer(device, callid, call,
458 usb_iface->interrupt_out);
459}
460
461void remote_usbhc_interrupt_in(device_t *device, void *iface,
462 ipc_callid_t callid, ipc_call_t *call)
463{
464 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
465 assert(usb_iface != NULL);
466
467 return remote_usbhc_in_transfer(device, callid, call,
468 usb_iface->interrupt_in);
469}
470
471void remote_usbhc_control_write_setup(device_t *device, void *iface,
472 ipc_callid_t callid, ipc_call_t *call)
473{
474 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
475 assert(usb_iface != NULL);
476
477 return remote_usbhc_out_transfer(device, callid, call,
478 usb_iface->control_write_setup);
479}
480
481void remote_usbhc_control_write_data(device_t *device, void *iface,
482 ipc_callid_t callid, ipc_call_t *call)
483{
484 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
485 assert(usb_iface != NULL);
486
487 return remote_usbhc_out_transfer(device, callid, call,
488 usb_iface->control_write_data);
489}
490
491void remote_usbhc_control_write_status(device_t *device, void *iface,
492 ipc_callid_t callid, ipc_call_t *call)
493{
494 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
495 assert(usb_iface != NULL);
496
497 return remote_usbhc_status_transfer(device, callid, call,
498 USB_DIRECTION_IN, usb_iface->control_write_status, NULL);
499}
500
501void remote_usbhc_control_read_setup(device_t *device, void *iface,
502 ipc_callid_t callid, ipc_call_t *call)
503{
504 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
505 assert(usb_iface != NULL);
506
507 return remote_usbhc_out_transfer(device, callid, call,
508 usb_iface->control_read_setup);
509}
510
511void remote_usbhc_control_read_data(device_t *device, void *iface,
512 ipc_callid_t callid, ipc_call_t *call)
513{
514 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
515 assert(usb_iface != NULL);
516
517 return remote_usbhc_in_transfer(device, callid, call,
518 usb_iface->control_read_data);
519}
520
521void remote_usbhc_control_read_status(device_t *device, void *iface,
522 ipc_callid_t callid, ipc_call_t *call)
523{
524 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
525 assert(usb_iface != NULL);
526
527 return remote_usbhc_status_transfer(device, callid, call,
528 USB_DIRECTION_OUT, NULL, usb_iface->control_read_status);
529}
530
531void remote_usbhc_control_write(device_t *device, void *iface,
532ipc_callid_t callid, ipc_call_t *call)
533{
534 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
535 assert(usb_iface != NULL);
536
537 if (!usb_iface->control_write) {
538 async_answer_0(callid, ENOTSUP);
539 return;
540 }
541
542 usb_target_t target = {
543 .address = DEV_IPC_GET_ARG1(*call),
544 .endpoint = DEV_IPC_GET_ARG2(*call)
545 };
546 size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
547
548 int rc;
549
550 void *setup_packet = NULL;
551 void *data_buffer = NULL;
552 size_t setup_packet_len = 0;
553
554 rc = async_data_write_accept(&setup_packet, false,
555 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
556 if (rc != EOK) {
557 async_answer_0(callid, rc);
558 return;
559 }
560
561 if (data_buffer_len > 0) {
562 rc = async_data_write_accept(&data_buffer, false,
563 1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
564 if (rc != EOK) {
565 async_answer_0(callid, rc);
566 free(setup_packet);
567 return;
568 }
569 }
570
571 async_transaction_t *trans = async_transaction_create(callid);
572 if (trans == NULL) {
573 async_answer_0(callid, ENOMEM);
574 free(setup_packet);
575 free(data_buffer);
576 return;
577 }
578 trans->setup_packet = setup_packet;
579 trans->buffer = data_buffer;
580 trans->size = data_buffer_len;
581
582 rc = usb_iface->control_write(device, target,
583 setup_packet, setup_packet_len,
584 data_buffer, data_buffer_len,
585 callback_out, trans);
586
587 if (rc != EOK) {
588 async_answer_0(callid, rc);
589 async_transaction_destroy(trans);
590 }
591}
592
593
594void remote_usbhc_control_read(device_t *device, void *iface,
595ipc_callid_t callid, ipc_call_t *call)
596{
597 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
598 assert(usb_iface != NULL);
599
600 if (!usb_iface->control_read) {
601 async_answer_0(callid, ENOTSUP);
602 return;
603 }
604
605 usb_target_t target = {
606 .address = DEV_IPC_GET_ARG1(*call),
607 .endpoint = DEV_IPC_GET_ARG2(*call)
608 };
609
610 int rc;
611
612 void *setup_packet = NULL;
613 size_t setup_packet_len = 0;
614 size_t data_len = 0;
615
616 rc = async_data_write_accept(&setup_packet, false,
617 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
618 if (rc != EOK) {
619 async_answer_0(callid, rc);
620 return;
621 }
622
623 ipc_callid_t data_callid;
624 if (!async_data_read_receive(&data_callid, &data_len)) {
625 async_answer_0(callid, EPARTY);
626 free(setup_packet);
627 return;
628 }
629
630 async_transaction_t *trans = async_transaction_create(callid);
631 if (trans == NULL) {
632 async_answer_0(callid, ENOMEM);
633 free(setup_packet);
634 return;
635 }
636 trans->data_caller = data_callid;
637 trans->setup_packet = setup_packet;
638 trans->size = data_len;
639 trans->buffer = malloc(data_len);
640 if (trans->buffer == NULL) {
641 async_answer_0(callid, ENOMEM);
642 async_transaction_destroy(trans);
643 return;
644 }
645
646 rc = usb_iface->control_read(device, target,
647 setup_packet, setup_packet_len,
648 trans->buffer, trans->size,
649 callback_in, trans);
650
651 if (rc != EOK) {
652 async_answer_0(callid, rc);
653 async_transaction_destroy(trans);
654 }
655}
656
657
658
659/**
660 * @}
661 */
Note: See TracBrowser for help on using the repository browser.