00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <async.h>
00036 #include <errno.h>
00037 #include <assert.h>
00038
00039 #include "usbhc_iface.h"
00040 #include "ddf/driver.h"
00041
00042 #define USB_MAX_PAYLOAD_SIZE 1020
00043 #define HACK_MAX_PACKET_SIZE 8
00044 #define HACK_MAX_PACKET_SIZE_INTERRUPT_IN 4
00045
00046 static void remote_usbhc_interrupt_out(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
00047 static void remote_usbhc_interrupt_in(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
00048 static void remote_usbhc_bulk_out(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
00049 static void remote_usbhc_bulk_in(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
00050 static void remote_usbhc_control_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
00051 static void remote_usbhc_control_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
00052 static void remote_usbhc_request_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
00053 static void remote_usbhc_bind_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
00054 static void remote_usbhc_find_by_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
00055 static void remote_usbhc_release_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
00056 static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
00057 static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
00058
00059
00061 static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
00062 remote_usbhc_request_address,
00063 remote_usbhc_bind_address,
00064 remote_usbhc_find_by_address,
00065 remote_usbhc_release_address,
00066
00067 remote_usbhc_interrupt_out,
00068 remote_usbhc_interrupt_in,
00069
00070 remote_usbhc_bulk_out,
00071 remote_usbhc_bulk_in,
00072
00073 remote_usbhc_control_write,
00074 remote_usbhc_control_read,
00075
00076 remote_usbhc_register_endpoint,
00077 remote_usbhc_unregister_endpoint
00078 };
00079
00082 remote_iface_t remote_usbhc_iface = {
00083 .method_count = sizeof(remote_usbhc_iface_ops) /
00084 sizeof(remote_usbhc_iface_ops[0]),
00085 .methods = remote_usbhc_iface_ops
00086 };
00087
00088 typedef struct {
00089 ipc_callid_t caller;
00090 ipc_callid_t data_caller;
00091 void *buffer;
00092 void *setup_packet;
00093 size_t size;
00094 } async_transaction_t;
00095
00096 static void async_transaction_destroy(async_transaction_t *trans)
00097 {
00098 if (trans == NULL) {
00099 return;
00100 }
00101
00102 if (trans->setup_packet != NULL) {
00103 free(trans->setup_packet);
00104 }
00105 if (trans->buffer != NULL) {
00106 free(trans->buffer);
00107 }
00108
00109 free(trans);
00110 }
00111
00112 static async_transaction_t *async_transaction_create(ipc_callid_t caller)
00113 {
00114 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
00115 if (trans == NULL) {
00116 return NULL;
00117 }
00118
00119 trans->caller = caller;
00120 trans->data_caller = 0;
00121 trans->buffer = NULL;
00122 trans->setup_packet = NULL;
00123 trans->size = 0;
00124
00125 return trans;
00126 }
00127
00128 void remote_usbhc_request_address(ddf_fun_t *fun, void *iface,
00129 ipc_callid_t callid, ipc_call_t *call)
00130 {
00131 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
00132
00133 if (!usb_iface->request_address) {
00134 async_answer_0(callid, ENOTSUP);
00135 return;
00136 }
00137
00138 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
00139
00140 usb_address_t address;
00141 int rc = usb_iface->request_address(fun, speed, &address);
00142 if (rc != EOK) {
00143 async_answer_0(callid, rc);
00144 } else {
00145 async_answer_1(callid, EOK, (sysarg_t) address);
00146 }
00147 }
00148
00149 void remote_usbhc_bind_address(ddf_fun_t *fun, void *iface,
00150 ipc_callid_t callid, ipc_call_t *call)
00151 {
00152 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
00153
00154 if (!usb_iface->bind_address) {
00155 async_answer_0(callid, ENOTSUP);
00156 return;
00157 }
00158
00159 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
00160 devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
00161
00162 int rc = usb_iface->bind_address(fun, address, handle);
00163
00164 async_answer_0(callid, rc);
00165 }
00166
00167 void remote_usbhc_find_by_address(ddf_fun_t *fun, void *iface,
00168 ipc_callid_t callid, ipc_call_t *call)
00169 {
00170 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
00171
00172 if (!usb_iface->find_by_address) {
00173 async_answer_0(callid, ENOTSUP);
00174 return;
00175 }
00176
00177 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
00178 devman_handle_t handle;
00179 int rc = usb_iface->find_by_address(fun, address, &handle);
00180
00181 if (rc == EOK) {
00182 async_answer_1(callid, EOK, handle);
00183 } else {
00184 async_answer_0(callid, rc);
00185 }
00186 }
00187
00188 void remote_usbhc_release_address(ddf_fun_t *fun, void *iface,
00189 ipc_callid_t callid, ipc_call_t *call)
00190 {
00191 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
00192
00193 if (!usb_iface->release_address) {
00194 async_answer_0(callid, ENOTSUP);
00195 return;
00196 }
00197
00198 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
00199
00200 int rc = usb_iface->release_address(fun, address);
00201
00202 async_answer_0(callid, rc);
00203 }
00204
00205
00206 static void callback_out(ddf_fun_t *fun,
00207 int outcome, void *arg)
00208 {
00209 async_transaction_t *trans = (async_transaction_t *)arg;
00210
00211 async_answer_0(trans->caller, outcome);
00212
00213 async_transaction_destroy(trans);
00214 }
00215
00216 static void callback_in(ddf_fun_t *fun,
00217 int outcome, size_t actual_size, void *arg)
00218 {
00219 async_transaction_t *trans = (async_transaction_t *)arg;
00220
00221 if (outcome != EOK) {
00222 async_answer_0(trans->caller, outcome);
00223 if (trans->data_caller) {
00224 async_answer_0(trans->data_caller, EINTR);
00225 }
00226 async_transaction_destroy(trans);
00227 return;
00228 }
00229
00230 trans->size = actual_size;
00231
00232 if (trans->data_caller) {
00233 async_data_read_finalize(trans->data_caller,
00234 trans->buffer, actual_size);
00235 }
00236
00237 async_answer_0(trans->caller, EOK);
00238
00239 async_transaction_destroy(trans);
00240 }
00241
00249 static void remote_usbhc_out_transfer(ddf_fun_t *fun,
00250 ipc_callid_t callid, ipc_call_t *call,
00251 usbhc_iface_transfer_out_t transfer_func)
00252 {
00253 if (!transfer_func) {
00254 async_answer_0(callid, ENOTSUP);
00255 return;
00256 }
00257
00258 usb_target_t target = {
00259 .address = DEV_IPC_GET_ARG1(*call),
00260 .endpoint = DEV_IPC_GET_ARG2(*call)
00261 };
00262
00263 size_t len = 0;
00264 void *buffer = NULL;
00265
00266 int rc = async_data_write_accept(&buffer, false,
00267 1, USB_MAX_PAYLOAD_SIZE,
00268 0, &len);
00269
00270 if (rc != EOK) {
00271 async_answer_0(callid, rc);
00272 return;
00273 }
00274
00275 async_transaction_t *trans = async_transaction_create(callid);
00276 if (trans == NULL) {
00277 if (buffer != NULL) {
00278 free(buffer);
00279 }
00280 async_answer_0(callid, ENOMEM);
00281 return;
00282 }
00283
00284 trans->buffer = buffer;
00285 trans->size = len;
00286
00287 rc = transfer_func(fun, target,
00288 buffer, len,
00289 callback_out, trans);
00290
00291 if (rc != EOK) {
00292 async_answer_0(callid, rc);
00293 async_transaction_destroy(trans);
00294 }
00295 }
00296
00304 static void remote_usbhc_in_transfer(ddf_fun_t *fun,
00305 ipc_callid_t callid, ipc_call_t *call,
00306 usbhc_iface_transfer_in_t transfer_func)
00307 {
00308 if (!transfer_func) {
00309 async_answer_0(callid, ENOTSUP);
00310 return;
00311 }
00312
00313 usb_target_t target = {
00314 .address = DEV_IPC_GET_ARG1(*call),
00315 .endpoint = DEV_IPC_GET_ARG2(*call)
00316 };
00317
00318 size_t len;
00319 ipc_callid_t data_callid;
00320 if (!async_data_read_receive(&data_callid, &len)) {
00321 async_answer_0(callid, EPARTY);
00322 return;
00323 }
00324
00325 async_transaction_t *trans = async_transaction_create(callid);
00326 if (trans == NULL) {
00327 async_answer_0(data_callid, ENOMEM);
00328 async_answer_0(callid, ENOMEM);
00329 return;
00330 }
00331 trans->data_caller = data_callid;
00332 trans->buffer = malloc(len);
00333 trans->size = len;
00334
00335 int rc = transfer_func(fun, target,
00336 trans->buffer, len,
00337 callback_in, trans);
00338
00339 if (rc != EOK) {
00340 async_answer_0(data_callid, rc);
00341 async_answer_0(callid, rc);
00342 async_transaction_destroy(trans);
00343 }
00344 }
00345
00346 void remote_usbhc_interrupt_out(ddf_fun_t *fun, void *iface,
00347 ipc_callid_t callid, ipc_call_t *call)
00348 {
00349 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
00350 assert(usb_iface != NULL);
00351
00352 return remote_usbhc_out_transfer(fun, callid, call,
00353 usb_iface->interrupt_out);
00354 }
00355
00356 void remote_usbhc_interrupt_in(ddf_fun_t *fun, void *iface,
00357 ipc_callid_t callid, ipc_call_t *call)
00358 {
00359 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
00360 assert(usb_iface != NULL);
00361
00362 return remote_usbhc_in_transfer(fun, callid, call,
00363 usb_iface->interrupt_in);
00364 }
00365
00366 void remote_usbhc_bulk_out(ddf_fun_t *fun, void *iface,
00367 ipc_callid_t callid, ipc_call_t *call)
00368 {
00369 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
00370 assert(usb_iface != NULL);
00371
00372 return remote_usbhc_out_transfer(fun, callid, call,
00373 usb_iface->bulk_out);
00374 }
00375
00376 void remote_usbhc_bulk_in(ddf_fun_t *fun, void *iface,
00377 ipc_callid_t callid, ipc_call_t *call)
00378 {
00379 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
00380 assert(usb_iface != NULL);
00381
00382 return remote_usbhc_in_transfer(fun, callid, call,
00383 usb_iface->bulk_in);
00384 }
00385
00386 void remote_usbhc_control_write(ddf_fun_t *fun, void *iface,
00387 ipc_callid_t callid, ipc_call_t *call)
00388 {
00389 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
00390 assert(usb_iface != NULL);
00391
00392 if (!usb_iface->control_write) {
00393 async_answer_0(callid, ENOTSUP);
00394 return;
00395 }
00396
00397 usb_target_t target = {
00398 .address = DEV_IPC_GET_ARG1(*call),
00399 .endpoint = DEV_IPC_GET_ARG2(*call)
00400 };
00401 size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
00402
00403 int rc;
00404
00405 void *setup_packet = NULL;
00406 void *data_buffer = NULL;
00407 size_t setup_packet_len = 0;
00408
00409 rc = async_data_write_accept(&setup_packet, false,
00410 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
00411 if (rc != EOK) {
00412 async_answer_0(callid, rc);
00413 return;
00414 }
00415
00416 if (data_buffer_len > 0) {
00417 rc = async_data_write_accept(&data_buffer, false,
00418 1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
00419 if (rc != EOK) {
00420 async_answer_0(callid, rc);
00421 free(setup_packet);
00422 return;
00423 }
00424 }
00425
00426 async_transaction_t *trans = async_transaction_create(callid);
00427 if (trans == NULL) {
00428 async_answer_0(callid, ENOMEM);
00429 free(setup_packet);
00430 free(data_buffer);
00431 return;
00432 }
00433 trans->setup_packet = setup_packet;
00434 trans->buffer = data_buffer;
00435 trans->size = data_buffer_len;
00436
00437 rc = usb_iface->control_write(fun, target,
00438 setup_packet, setup_packet_len,
00439 data_buffer, data_buffer_len,
00440 callback_out, trans);
00441
00442 if (rc != EOK) {
00443 async_answer_0(callid, rc);
00444 async_transaction_destroy(trans);
00445 }
00446 }
00447
00448
00449 void remote_usbhc_control_read(ddf_fun_t *fun, void *iface,
00450 ipc_callid_t callid, ipc_call_t *call)
00451 {
00452 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
00453 assert(usb_iface != NULL);
00454
00455 if (!usb_iface->control_read) {
00456 async_answer_0(callid, ENOTSUP);
00457 return;
00458 }
00459
00460 usb_target_t target = {
00461 .address = DEV_IPC_GET_ARG1(*call),
00462 .endpoint = DEV_IPC_GET_ARG2(*call)
00463 };
00464
00465 int rc;
00466
00467 void *setup_packet = NULL;
00468 size_t setup_packet_len = 0;
00469 size_t data_len = 0;
00470
00471 rc = async_data_write_accept(&setup_packet, false,
00472 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
00473 if (rc != EOK) {
00474 async_answer_0(callid, rc);
00475 return;
00476 }
00477
00478 ipc_callid_t data_callid;
00479 if (!async_data_read_receive(&data_callid, &data_len)) {
00480 async_answer_0(callid, EPARTY);
00481 free(setup_packet);
00482 return;
00483 }
00484
00485 async_transaction_t *trans = async_transaction_create(callid);
00486 if (trans == NULL) {
00487 async_answer_0(data_callid, ENOMEM);
00488 async_answer_0(callid, ENOMEM);
00489 free(setup_packet);
00490 return;
00491 }
00492 trans->data_caller = data_callid;
00493 trans->setup_packet = setup_packet;
00494 trans->size = data_len;
00495 trans->buffer = malloc(data_len);
00496 if (trans->buffer == NULL) {
00497 async_answer_0(data_callid, ENOMEM);
00498 async_answer_0(callid, ENOMEM);
00499 async_transaction_destroy(trans);
00500 return;
00501 }
00502
00503 rc = usb_iface->control_read(fun, target,
00504 setup_packet, setup_packet_len,
00505 trans->buffer, trans->size,
00506 callback_in, trans);
00507
00508 if (rc != EOK) {
00509 async_answer_0(data_callid, rc);
00510 async_answer_0(callid, rc);
00511 async_transaction_destroy(trans);
00512 }
00513 }
00514
00515
00516 void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
00517 ipc_callid_t callid, ipc_call_t *call)
00518 {
00519 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
00520
00521 if (!usb_iface->register_endpoint) {
00522 async_answer_0(callid, ENOTSUP);
00523 return;
00524 }
00525
00526 #define _INIT_FROM_HIGH_DATA2(type, var, arg_no) \
00527 type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
00528 #define _INIT_FROM_LOW_DATA2(type, var, arg_no) \
00529 type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 16)
00530 #define _INIT_FROM_HIGH_DATA3(type, var, arg_no) \
00531 type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
00532 #define _INIT_FROM_MIDDLE_DATA3(type, var, arg_no) \
00533 type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) / (1 << 8)) % (1 << 8)
00534 #define _INIT_FROM_LOW_DATA3(type, var, arg_no) \
00535 type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 8)
00536
00537 _INIT_FROM_HIGH_DATA2(usb_address_t, address, 1);
00538 _INIT_FROM_LOW_DATA2(usb_endpoint_t, endpoint, 1);
00539
00540 _INIT_FROM_HIGH_DATA3(usb_speed_t, speed, 2);
00541 _INIT_FROM_MIDDLE_DATA3(usb_transfer_type_t, transfer_type, 2);
00542 _INIT_FROM_LOW_DATA3(usb_direction_t, direction, 2);
00543
00544 _INIT_FROM_HIGH_DATA2(size_t, max_packet_size, 3);
00545 _INIT_FROM_LOW_DATA2(unsigned int, interval, 3);
00546
00547 #undef _INIT_FROM_HIGH_DATA2
00548 #undef _INIT_FROM_LOW_DATA2
00549 #undef _INIT_FROM_HIGH_DATA3
00550 #undef _INIT_FROM_MIDDLE_DATA3
00551 #undef _INIT_FROM_LOW_DATA3
00552
00553 int rc = usb_iface->register_endpoint(fun, address, speed, endpoint,
00554 transfer_type, direction, max_packet_size, interval);
00555
00556 async_answer_0(callid, rc);
00557 }
00558
00559
00560 void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
00561 ipc_callid_t callid, ipc_call_t *call)
00562 {
00563 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
00564
00565 if (!usb_iface->unregister_endpoint) {
00566 async_answer_0(callid, ENOTSUP);
00567 return;
00568 }
00569
00570 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
00571 usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG2(*call);
00572 usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG3(*call);
00573
00574 int rc = usb_iface->unregister_endpoint(fun,
00575 address, endpoint, direction);
00576
00577 async_answer_0(callid, rc);
00578 }
00579
00580