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

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

Merge mainline changes (DDF refactoring)

This merge includes DDF refactoring that brought multifunctional devices
(i.e. ddf_dev_t and ddf_fun_t). Please, see ticket #295 at HelenOS
upstream Trac.

The conflicts themselves were easy to solve (merely several renamings).

Changes to USB subsystem:

  • drivers uses ddf_dev_t and ddf_fun_t
  • different signatures of many library functions
  • several hacks around communication with parent device (now the communication is clearer and somehow what we have now is hack about other hacks)
    • will repair and clean later
  • maybe added some extra debugging messages (the diff has about 240K, and I admit I have no energy to double check that)

WARNING:

  • the diff is VERY long, recommended is viewing partial diffs of the merge (i.e. merges in mainline branch that lead to the parent one)
  • merging with your branches might involve huge renamings, sorry, no other way is possible

BUGS:

  • hub driver will not work (no function created)

GOOD NEWS:

  • QEMU keyboard seems to work with QEMU 0.13 and 0.14
  • we are up-to-date with mainline again
  • Property mode set to 100644
File size: 13.2 KB
RevLine 
[91db50ac]1/*
[9753220]2 * Copyright (c) 2010-2011 Vojtech Horky
[91db50ac]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>
[eb1a2f4]37#include <assert.h>
[91db50ac]38
[cb59f787]39#include "usbhc_iface.h"
[eb1a2f4]40#include "ddf/driver.h"
[91db50ac]41
[1b22bd4]42#define USB_MAX_PAYLOAD_SIZE 1020
[ec59693]43#define HACK_MAX_PACKET_SIZE 8
44#define HACK_MAX_PACKET_SIZE_INTERRUPT_IN 4
[1b22bd4]45
[eb1a2f4]46static void remote_usbhc_interrupt_out(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
47static void remote_usbhc_interrupt_in(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
48static void remote_usbhc_bulk_out(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
49static void remote_usbhc_bulk_in(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
50static void remote_usbhc_control_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
51static void remote_usbhc_control_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
52static void remote_usbhc_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
53static void remote_usbhc_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
54static void remote_usbhc_request_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
55static void remote_usbhc_bind_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
56static void remote_usbhc_release_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
57//static void remote_usbhc(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
[91db50ac]58
[6edd494]59/** Remote USB host controller interface operations. */
[cb59f787]60static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
[6f04905]61 remote_usbhc_reserve_default_address,
62 remote_usbhc_release_default_address,
63
64 remote_usbhc_request_address,
[4689d40]65 remote_usbhc_bind_address,
[6f04905]66 remote_usbhc_release_address,
67
[aae339e9]68 remote_usbhc_interrupt_out,
[a3dfb2e]69 remote_usbhc_interrupt_in,
[6f04905]70
[0a46c41e]71 remote_usbhc_bulk_out,
72 remote_usbhc_bulk_in,
73
[9753220]74 remote_usbhc_control_write,
75 remote_usbhc_control_read
[91db50ac]76};
77
[6edd494]78/** Remote USB host controller interface structure.
[91db50ac]79 */
[cb59f787]80remote_iface_t remote_usbhc_iface = {
81 .method_count = sizeof(remote_usbhc_iface_ops) /
82 sizeof(remote_usbhc_iface_ops[0]),
83 .methods = remote_usbhc_iface_ops
[91db50ac]84};
85
[1b22bd4]86typedef struct {
87 ipc_callid_t caller;
[0a6fa9f]88 ipc_callid_t data_caller;
[1b22bd4]89 void *buffer;
[9753220]90 void *setup_packet;
[1b22bd4]91 size_t size;
92} async_transaction_t;
[91db50ac]93
[93f8da1]94static void async_transaction_destroy(async_transaction_t *trans)
95{
96 if (trans == NULL) {
97 return;
98 }
99
100 if (trans->setup_packet != NULL) {
101 free(trans->setup_packet);
102 }
103 if (trans->buffer != NULL) {
104 free(trans->buffer);
105 }
106
107 free(trans);
108}
109
110static async_transaction_t *async_transaction_create(ipc_callid_t caller)
111{
112 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
113 if (trans == NULL) {
114 return NULL;
115 }
116
117 trans->caller = caller;
[0a6fa9f]118 trans->data_caller = 0;
[93f8da1]119 trans->buffer = NULL;
120 trans->setup_packet = NULL;
121 trans->size = 0;
122
123 return trans;
124}
125
[eb1a2f4]126void remote_usbhc_reserve_default_address(ddf_fun_t *fun, void *iface,
[6f04905]127 ipc_callid_t callid, ipc_call_t *call)
128{
129 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
130
131 if (!usb_iface->reserve_default_address) {
[17aca1c]132 async_answer_0(callid, ENOTSUP);
[6f04905]133 return;
134 }
[6427cf67]135
[fa48ebe]136 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
[6427cf67]137
[eb1a2f4]138 int rc = usb_iface->reserve_default_address(fun, speed);
[6f04905]139
[17aca1c]140 async_answer_0(callid, rc);
[6f04905]141}
142
[eb1a2f4]143void remote_usbhc_release_default_address(ddf_fun_t *fun, void *iface,
[6f04905]144 ipc_callid_t callid, ipc_call_t *call)
145{
146 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
147
148 if (!usb_iface->release_default_address) {
[17aca1c]149 async_answer_0(callid, ENOTSUP);
[6f04905]150 return;
151 }
152
[eb1a2f4]153 int rc = usb_iface->release_default_address(fun);
[6f04905]154
[17aca1c]155 async_answer_0(callid, rc);
[6f04905]156}
157
[eb1a2f4]158void remote_usbhc_request_address(ddf_fun_t *fun, void *iface,
[6f04905]159 ipc_callid_t callid, ipc_call_t *call)
160{
161 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
162
163 if (!usb_iface->request_address) {
[17aca1c]164 async_answer_0(callid, ENOTSUP);
[6f04905]165 return;
166 }
[6427cf67]167
[fa48ebe]168 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
[6f04905]169
170 usb_address_t address;
[eb1a2f4]171 int rc = usb_iface->request_address(fun, speed, &address);
[6f04905]172 if (rc != EOK) {
[17aca1c]173 async_answer_0(callid, rc);
[6f04905]174 } else {
[17aca1c]175 async_answer_1(callid, EOK, (sysarg_t) address);
[6f04905]176 }
177}
178
[eb1a2f4]179void remote_usbhc_bind_address(ddf_fun_t *fun, void *iface,
[4689d40]180 ipc_callid_t callid, ipc_call_t *call)
181{
182 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
183
184 if (!usb_iface->bind_address) {
[17aca1c]185 async_answer_0(callid, ENOTSUP);
[4689d40]186 return;
187 }
188
[eac610e]189 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
190 devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
[4689d40]191
[eb1a2f4]192 int rc = usb_iface->bind_address(fun, address, handle);
[4689d40]193
[17aca1c]194 async_answer_0(callid, rc);
[4689d40]195}
196
[eb1a2f4]197void remote_usbhc_release_address(ddf_fun_t *fun, void *iface,
[6f04905]198 ipc_callid_t callid, ipc_call_t *call)
199{
200 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
201
202 if (!usb_iface->release_address) {
[17aca1c]203 async_answer_0(callid, ENOTSUP);
[6f04905]204 return;
205 }
206
[eac610e]207 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
[6f04905]208
[eb1a2f4]209 int rc = usb_iface->release_address(fun, address);
[6f04905]210
[17aca1c]211 async_answer_0(callid, rc);
[6f04905]212}
213
[1b22bd4]214
[eb1a2f4]215static void callback_out(ddf_fun_t *fun,
[daec5e04]216 int outcome, void *arg)
[1b22bd4]217{
218 async_transaction_t *trans = (async_transaction_t *)arg;
219
[17aca1c]220 async_answer_0(trans->caller, outcome);
[1b22bd4]221
[93f8da1]222 async_transaction_destroy(trans);
[1b22bd4]223}
224
[eb1a2f4]225static void callback_in(ddf_fun_t *fun,
[daec5e04]226 int outcome, size_t actual_size, void *arg)
[1b22bd4]227{
228 async_transaction_t *trans = (async_transaction_t *)arg;
229
[daec5e04]230 if (outcome != EOK) {
[17aca1c]231 async_answer_0(trans->caller, outcome);
[5842493]232 if (trans->data_caller) {
233 async_answer_0(trans->data_caller, EINTR);
234 }
[93f8da1]235 async_transaction_destroy(trans);
236 return;
237 }
[1b22bd4]238
239 trans->size = actual_size;
[0a6fa9f]240
241 if (trans->data_caller) {
242 async_data_read_finalize(trans->data_caller,
243 trans->buffer, actual_size);
244 }
245
[daec5e04]246 async_answer_0(trans->caller, EOK);
[1e64b250]247
248 async_transaction_destroy(trans);
[91db50ac]249}
250
[fb1dca09]251/** Process an outgoing transfer (both OUT and SETUP).
252 *
253 * @param device Target device.
254 * @param callid Initiating caller.
255 * @param call Initiating call.
256 * @param transfer_func Transfer function (might be NULL).
257 */
[eb1a2f4]258static void remote_usbhc_out_transfer(ddf_fun_t *fun,
[fb1dca09]259 ipc_callid_t callid, ipc_call_t *call,
260 usbhc_iface_transfer_out_t transfer_func)
[91db50ac]261{
[fb1dca09]262 if (!transfer_func) {
[17aca1c]263 async_answer_0(callid, ENOTSUP);
[fb1dca09]264 return;
265 }
[1b22bd4]266
[228f251]267 size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
[1b22bd4]268 usb_target_t target = {
[eac610e]269 .address = DEV_IPC_GET_ARG1(*call),
270 .endpoint = DEV_IPC_GET_ARG2(*call)
[1b22bd4]271 };
272
273 size_t len = 0;
274 void *buffer = NULL;
275
[228f251]276 int rc = async_data_write_accept(&buffer, false,
277 1, USB_MAX_PAYLOAD_SIZE,
278 0, &len);
279
280 if (rc != EOK) {
281 async_answer_0(callid, rc);
282 return;
[1b22bd4]283 }
284
[93f8da1]285 async_transaction_t *trans = async_transaction_create(callid);
286 if (trans == NULL) {
287 if (buffer != NULL) {
288 free(buffer);
289 }
[17aca1c]290 async_answer_0(callid, ENOMEM);
[93f8da1]291 return;
292 }
293
[fb1dca09]294 trans->buffer = buffer;
295 trans->size = len;
[1b22bd4]296
[eb1a2f4]297 rc = transfer_func(fun, target, max_packet_size,
[ec59693]298 buffer, len,
[1b22bd4]299 callback_out, trans);
300
301 if (rc != EOK) {
[17aca1c]302 async_answer_0(callid, rc);
[93f8da1]303 async_transaction_destroy(trans);
[1b22bd4]304 }
[91db50ac]305}
306
[fb1dca09]307/** Process an incoming transfer.
308 *
309 * @param device Target device.
310 * @param callid Initiating caller.
311 * @param call Initiating call.
312 * @param transfer_func Transfer function (might be NULL).
313 */
[eb1a2f4]314static void remote_usbhc_in_transfer(ddf_fun_t *fun,
[fb1dca09]315 ipc_callid_t callid, ipc_call_t *call,
316 usbhc_iface_transfer_in_t transfer_func)
[91db50ac]317{
[fb1dca09]318 if (!transfer_func) {
[17aca1c]319 async_answer_0(callid, ENOTSUP);
[fb1dca09]320 return;
321 }
[1b22bd4]322
[228f251]323 size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
[1b22bd4]324 usb_target_t target = {
[eac610e]325 .address = DEV_IPC_GET_ARG1(*call),
326 .endpoint = DEV_IPC_GET_ARG2(*call)
[1b22bd4]327 };
328
[228f251]329 size_t len;
[0a6fa9f]330 ipc_callid_t data_callid;
331 if (!async_data_read_receive(&data_callid, &len)) {
332 async_answer_0(callid, EPARTY);
333 return;
334 }
335
[93f8da1]336 async_transaction_t *trans = async_transaction_create(callid);
337 if (trans == NULL) {
[17aca1c]338 async_answer_0(callid, ENOMEM);
[93f8da1]339 return;
340 }
[0a6fa9f]341 trans->data_caller = data_callid;
[1b22bd4]342 trans->buffer = malloc(len);
343 trans->size = len;
344
[eb1a2f4]345 int rc = transfer_func(fun, target, max_packet_size,
[ec59693]346 trans->buffer, len,
[1b22bd4]347 callback_in, trans);
348
349 if (rc != EOK) {
[17aca1c]350 async_answer_0(callid, rc);
[93f8da1]351 async_transaction_destroy(trans);
[1b22bd4]352 }
[91db50ac]353}
354
[eb1a2f4]355void remote_usbhc_interrupt_out(ddf_fun_t *fun, void *iface,
[fb1dca09]356 ipc_callid_t callid, ipc_call_t *call)
[a3dfb2e]357{
358 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
[fb1dca09]359 assert(usb_iface != NULL);
[a3dfb2e]360
[eb1a2f4]361 return remote_usbhc_out_transfer(fun, callid, call,
[fb1dca09]362 usb_iface->interrupt_out);
363}
[a3dfb2e]364
[eb1a2f4]365void remote_usbhc_interrupt_in(ddf_fun_t *fun, void *iface,
[fb1dca09]366 ipc_callid_t callid, ipc_call_t *call)
367{
368 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
369 assert(usb_iface != NULL);
[a3dfb2e]370
[eb1a2f4]371 return remote_usbhc_in_transfer(fun, callid, call,
[fb1dca09]372 usb_iface->interrupt_in);
373}
[a3dfb2e]374
[eb1a2f4]375void remote_usbhc_bulk_out(ddf_fun_t *fun, void *iface,
[0a46c41e]376 ipc_callid_t callid, ipc_call_t *call)
377{
378 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
379 assert(usb_iface != NULL);
380
[eb1a2f4]381 return remote_usbhc_out_transfer(fun, callid, call,
[0a46c41e]382 usb_iface->bulk_out);
383}
384
[eb1a2f4]385void remote_usbhc_bulk_in(ddf_fun_t *fun, void *iface,
[0a46c41e]386 ipc_callid_t callid, ipc_call_t *call)
387{
388 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
389 assert(usb_iface != NULL);
390
[eb1a2f4]391 return remote_usbhc_in_transfer(fun, callid, call,
[0a46c41e]392 usb_iface->bulk_in);
393}
394
[eb1a2f4]395void remote_usbhc_control_write(ddf_fun_t *fun, void *iface,
[9753220]396ipc_callid_t callid, ipc_call_t *call)
397{
398 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
399 assert(usb_iface != NULL);
400
401 if (!usb_iface->control_write) {
[17aca1c]402 async_answer_0(callid, ENOTSUP);
[9753220]403 return;
404 }
405
406 usb_target_t target = {
407 .address = DEV_IPC_GET_ARG1(*call),
408 .endpoint = DEV_IPC_GET_ARG2(*call)
409 };
[3937bda]410 size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
[228f251]411 size_t max_packet_size = DEV_IPC_GET_ARG4(*call);
[9753220]412
413 int rc;
414
415 void *setup_packet = NULL;
416 void *data_buffer = NULL;
417 size_t setup_packet_len = 0;
418
419 rc = async_data_write_accept(&setup_packet, false,
420 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
421 if (rc != EOK) {
[17aca1c]422 async_answer_0(callid, rc);
[9753220]423 return;
424 }
[3937bda]425
426 if (data_buffer_len > 0) {
427 rc = async_data_write_accept(&data_buffer, false,
428 1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
429 if (rc != EOK) {
430 async_answer_0(callid, rc);
431 free(setup_packet);
432 return;
433 }
[9753220]434 }
435
[93f8da1]436 async_transaction_t *trans = async_transaction_create(callid);
437 if (trans == NULL) {
[17aca1c]438 async_answer_0(callid, ENOMEM);
[93f8da1]439 free(setup_packet);
440 free(data_buffer);
441 return;
442 }
[9753220]443 trans->setup_packet = setup_packet;
444 trans->buffer = data_buffer;
445 trans->size = data_buffer_len;
446
[eb1a2f4]447 rc = usb_iface->control_write(fun, target, max_packet_size,
[9753220]448 setup_packet, setup_packet_len,
449 data_buffer, data_buffer_len,
450 callback_out, trans);
451
452 if (rc != EOK) {
[17aca1c]453 async_answer_0(callid, rc);
[93f8da1]454 async_transaction_destroy(trans);
[9753220]455 }
456}
457
458
[eb1a2f4]459void remote_usbhc_control_read(ddf_fun_t *fun, void *iface,
[9753220]460ipc_callid_t callid, ipc_call_t *call)
461{
462 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
463 assert(usb_iface != NULL);
464
465 if (!usb_iface->control_read) {
[17aca1c]466 async_answer_0(callid, ENOTSUP);
[9753220]467 return;
468 }
469
470 usb_target_t target = {
471 .address = DEV_IPC_GET_ARG1(*call),
472 .endpoint = DEV_IPC_GET_ARG2(*call)
473 };
[228f251]474 size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
[9753220]475
476 int rc;
477
478 void *setup_packet = NULL;
479 size_t setup_packet_len = 0;
[3937bda]480 size_t data_len = 0;
[9753220]481
482 rc = async_data_write_accept(&setup_packet, false,
483 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
484 if (rc != EOK) {
[17aca1c]485 async_answer_0(callid, rc);
[9753220]486 return;
487 }
488
[0a6fa9f]489 ipc_callid_t data_callid;
490 if (!async_data_read_receive(&data_callid, &data_len)) {
491 async_answer_0(callid, EPARTY);
492 free(setup_packet);
493 return;
494 }
495
[93f8da1]496 async_transaction_t *trans = async_transaction_create(callid);
497 if (trans == NULL) {
[17aca1c]498 async_answer_0(callid, ENOMEM);
[93f8da1]499 free(setup_packet);
500 return;
501 }
[0a6fa9f]502 trans->data_caller = data_callid;
[9753220]503 trans->setup_packet = setup_packet;
504 trans->size = data_len;
[93f8da1]505 trans->buffer = malloc(data_len);
506 if (trans->buffer == NULL) {
[17aca1c]507 async_answer_0(callid, ENOMEM);
[93f8da1]508 async_transaction_destroy(trans);
509 return;
510 }
[9753220]511
[eb1a2f4]512 rc = usb_iface->control_read(fun, target, max_packet_size,
[9753220]513 setup_packet, setup_packet_len,
514 trans->buffer, trans->size,
515 callback_in, trans);
516
517 if (rc != EOK) {
[17aca1c]518 async_answer_0(callid, rc);
[93f8da1]519 async_transaction_destroy(trans);
[9753220]520 }
521}
522
[a3dfb2e]523
[1b22bd4]524
[91db50ac]525/**
526 * @}
527 */
Note: See TracBrowser for help on using the repository browser.