remote_usbhc.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010-2011 Vojtech Horky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 //static void remote_usbhc(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
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 

Generated on Thu Jun 2 07:45:47 2011 for HelenOS/USB by  doxygen 1.4.7