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

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

Removal of remote parts of old API

The control transfer callbacks for each part of the transfer
(i.e. for setup, data and status) were completely removed.

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