[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] | 45 | static void remote_usbhc_get_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
|
---|
[cb59f787] | 46 | static void remote_usbhc_interrupt_out(device_t *, void *, ipc_callid_t, ipc_call_t *);
|
---|
| 47 | static void remote_usbhc_interrupt_in(device_t *, void *, ipc_callid_t, ipc_call_t *);
|
---|
[9753220] | 48 | static void remote_usbhc_control_write(device_t *, void *, ipc_callid_t, ipc_call_t *);
|
---|
| 49 | static void remote_usbhc_control_read(device_t *, void *, ipc_callid_t, ipc_call_t *);
|
---|
[6f04905] | 50 | static void remote_usbhc_reserve_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
|
---|
| 51 | static void remote_usbhc_release_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
|
---|
| 52 | static void remote_usbhc_request_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
|
---|
[4689d40] | 53 | static void remote_usbhc_bind_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
|
---|
[6f04905] | 54 | static 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] | 58 | static 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] | 77 | remote_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] | 83 | typedef 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] | 91 | static 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 |
|
---|
| 107 | static 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] | 123 | void 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] | 144 | void 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 |
|
---|
| 161 | void 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 |
|
---|
| 176 | void 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] | 197 | void 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] | 215 | void 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 |
|
---|
| 233 | static 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 |
|
---|
| 243 | static 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 | */
|
---|
| 276 | static 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 | */
|
---|
| 332 | static 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] | 373 | void 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] | 383 | void 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] | 393 | void remote_usbhc_control_write(device_t *device, void *iface,
|
---|
| 394 | ipc_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 |
|
---|
| 457 | void remote_usbhc_control_read(device_t *device, void *iface,
|
---|
| 458 | ipc_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 | */
|
---|