pipesio.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 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 
00046 #include <usb/usb.h>
00047 #include <usb/dev/pipes.h>
00048 #include <errno.h>
00049 #include <assert.h>
00050 #include <usbhc_iface.h>
00051 #include <usb/dev/request.h>
00052 #include "pipepriv.h"
00053 
00062 static int usb_pipe_read_no_checks(usb_pipe_t *pipe,
00063     void *buffer, size_t size, size_t *size_transfered)
00064 {
00065         /*
00066          * Get corresponding IPC method.
00067          * In future, replace with static array of mappings
00068          * transfer type -> method.
00069          */
00070         usbhc_iface_funcs_t ipc_method;
00071         switch (pipe->transfer_type) {
00072                 case USB_TRANSFER_INTERRUPT:
00073                         ipc_method = IPC_M_USBHC_INTERRUPT_IN;
00074                         break;
00075                 case USB_TRANSFER_BULK:
00076                         ipc_method = IPC_M_USBHC_BULK_IN;
00077                         break;
00078                 default:
00079                         return ENOTSUP;
00080         }
00081 
00082         /* Ensure serialization over the phone. */
00083         pipe_start_transaction(pipe);
00084 
00085         /*
00086          * Make call identifying target USB device and type of transfer.
00087          */
00088         aid_t opening_request = async_send_3(pipe->hc_phone,
00089             DEV_IFACE_ID(USBHC_DEV_IFACE), ipc_method,
00090             pipe->wire->address, pipe->endpoint_no,
00091             NULL);
00092         if (opening_request == 0) {
00093                 pipe_end_transaction(pipe);
00094                 return ENOMEM;
00095         }
00096 
00097         /*
00098          * Retrieve the data.
00099          */
00100         ipc_call_t data_request_call;
00101         aid_t data_request = async_data_read(pipe->hc_phone, buffer, size,
00102             &data_request_call);
00103 
00104         /*
00105          * Since now on, someone else might access the backing phone
00106          * without breaking the transfer IPC protocol.
00107          */
00108         pipe_end_transaction(pipe);
00109 
00110         if (data_request == 0) {
00111                 /*
00112                  * FIXME:
00113                  * How to let the other side know that we want to abort?
00114                  */
00115                 async_wait_for(opening_request, NULL);
00116                 return ENOMEM;
00117         }
00118 
00119         /*
00120          * Wait for the answer.
00121          */
00122         sysarg_t data_request_rc;
00123         sysarg_t opening_request_rc;
00124         async_wait_for(data_request, &data_request_rc);
00125         async_wait_for(opening_request, &opening_request_rc);
00126 
00127         if (data_request_rc != EOK) {
00128                 /* Prefer the return code of the opening request. */
00129                 if (opening_request_rc != EOK) {
00130                         return (int) opening_request_rc;
00131                 } else {
00132                         return (int) data_request_rc;
00133                 }
00134         }
00135         if (opening_request_rc != EOK) {
00136                 return (int) opening_request_rc;
00137         }
00138 
00139         *size_transfered = IPC_GET_ARG2(data_request_call);
00140 
00141         return EOK;
00142 }
00143 
00144 
00153 int usb_pipe_read(usb_pipe_t *pipe,
00154     void *buffer, size_t size, size_t *size_transfered)
00155 {
00156         assert(pipe);
00157 
00158         if (buffer == NULL) {
00159                 return EINVAL;
00160         }
00161 
00162         if (size == 0) {
00163                 return EINVAL;
00164         }
00165 
00166         if (pipe->direction != USB_DIRECTION_IN) {
00167                 return EBADF;
00168         }
00169 
00170         if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
00171                 return EBADF;
00172         }
00173 
00174         int rc;
00175         rc = pipe_add_ref(pipe, false);
00176         if (rc != EOK) {
00177                 return rc;
00178         }
00179 
00180 
00181         size_t act_size = 0;
00182 
00183         rc = usb_pipe_read_no_checks(pipe, buffer, size, &act_size);
00184 
00185         pipe_drop_ref(pipe);
00186 
00187         if (rc != EOK) {
00188                 return rc;
00189         }
00190 
00191         if (size_transfered != NULL) {
00192                 *size_transfered = act_size;
00193         }
00194 
00195         return EOK;
00196 }
00197 
00198 
00199 
00200 
00208 static int usb_pipe_write_no_check(usb_pipe_t *pipe,
00209     void *buffer, size_t size)
00210 {
00211         /*
00212          * Get corresponding IPC method.
00213          * In future, replace with static array of mappings
00214          * transfer type -> method.
00215          */
00216         usbhc_iface_funcs_t ipc_method;
00217         switch (pipe->transfer_type) {
00218                 case USB_TRANSFER_INTERRUPT:
00219                         ipc_method = IPC_M_USBHC_INTERRUPT_OUT;
00220                         break;
00221                 case USB_TRANSFER_BULK:
00222                         ipc_method = IPC_M_USBHC_BULK_OUT;
00223                         break;
00224                 default:
00225                         return ENOTSUP;
00226         }
00227 
00228         /* Ensure serialization over the phone. */
00229         pipe_start_transaction(pipe);
00230 
00231         /*
00232          * Make call identifying target USB device and type of transfer.
00233          */
00234         aid_t opening_request = async_send_3(pipe->hc_phone,
00235             DEV_IFACE_ID(USBHC_DEV_IFACE), ipc_method,
00236             pipe->wire->address, pipe->endpoint_no,
00237             NULL);
00238         if (opening_request == 0) {
00239                 pipe_end_transaction(pipe);
00240                 return ENOMEM;
00241         }
00242 
00243         /*
00244          * Send the data.
00245          */
00246         int rc = async_data_write_start(pipe->hc_phone, buffer, size);
00247 
00248         /*
00249          * Since now on, someone else might access the backing phone
00250          * without breaking the transfer IPC protocol.
00251          */
00252         pipe_end_transaction(pipe);
00253 
00254         if (rc != EOK) {
00255                 async_wait_for(opening_request, NULL);
00256                 return rc;
00257         }
00258 
00259         /*
00260          * Wait for the answer.
00261          */
00262         sysarg_t opening_request_rc;
00263         async_wait_for(opening_request, &opening_request_rc);
00264 
00265         return (int) opening_request_rc;
00266 }
00267 
00275 int usb_pipe_write(usb_pipe_t *pipe,
00276     void *buffer, size_t size)
00277 {
00278         assert(pipe);
00279 
00280         if (buffer == NULL) {
00281                 return EINVAL;
00282         }
00283 
00284         if (size == 0) {
00285                 return EINVAL;
00286         }
00287 
00288         if (pipe->direction != USB_DIRECTION_OUT) {
00289                 return EBADF;
00290         }
00291 
00292         if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
00293                 return EBADF;
00294         }
00295 
00296         int rc;
00297 
00298         rc = pipe_add_ref(pipe, false);
00299         if (rc != EOK) {
00300                 return rc;
00301         }
00302 
00303         rc = usb_pipe_write_no_check(pipe, buffer, size);
00304 
00305         pipe_drop_ref(pipe);
00306 
00307         return rc;
00308 }
00309 
00314 static void clear_self_endpoint_halt(usb_pipe_t *pipe)
00315 {
00316         assert(pipe != NULL);
00317 
00318         if (!pipe->auto_reset_halt || (pipe->endpoint_no != 0)) {
00319                 return;
00320         }
00321 
00322 
00323         /* Prevent indefinite recursion. */
00324         pipe->auto_reset_halt = false;
00325         usb_request_clear_endpoint_halt(pipe, 0);
00326         pipe->auto_reset_halt = true;
00327 }
00328 
00329 
00341 static int usb_pipe_control_read_no_check(usb_pipe_t *pipe,
00342     void *setup_buffer, size_t setup_buffer_size,
00343     void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
00344 {
00345         /* Ensure serialization over the phone. */
00346         pipe_start_transaction(pipe);
00347 
00348         /*
00349          * Make call identifying target USB device and control transfer type.
00350          */
00351         aid_t opening_request = async_send_3(pipe->hc_phone,
00352             DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_CONTROL_READ,
00353             pipe->wire->address, pipe->endpoint_no,
00354             NULL);
00355         if (opening_request == 0) {
00356                 return ENOMEM;
00357         }
00358 
00359         /*
00360          * Send the setup packet.
00361          */
00362         int rc = async_data_write_start(pipe->hc_phone,
00363             setup_buffer, setup_buffer_size);
00364         if (rc != EOK) {
00365                 pipe_end_transaction(pipe);
00366                 async_wait_for(opening_request, NULL);
00367                 return rc;
00368         }
00369 
00370         /*
00371          * Retrieve the data.
00372          */
00373         ipc_call_t data_request_call;
00374         aid_t data_request = async_data_read(pipe->hc_phone,
00375             data_buffer, data_buffer_size,
00376             &data_request_call);
00377 
00378         /*
00379          * Since now on, someone else might access the backing phone
00380          * without breaking the transfer IPC protocol.
00381          */
00382         pipe_end_transaction(pipe);
00383 
00384 
00385         if (data_request == 0) {
00386                 async_wait_for(opening_request, NULL);
00387                 return ENOMEM;
00388         }
00389 
00390         /*
00391          * Wait for the answer.
00392          */
00393         sysarg_t data_request_rc;
00394         sysarg_t opening_request_rc;
00395         async_wait_for(data_request, &data_request_rc);
00396         async_wait_for(opening_request, &opening_request_rc);
00397 
00398         if (data_request_rc != EOK) {
00399                 /* Prefer the return code of the opening request. */
00400                 if (opening_request_rc != EOK) {
00401                         return (int) opening_request_rc;
00402                 } else {
00403                         return (int) data_request_rc;
00404                 }
00405         }
00406         if (opening_request_rc != EOK) {
00407                 return (int) opening_request_rc;
00408         }
00409 
00410         *data_transfered_size = IPC_GET_ARG2(data_request_call);
00411 
00412         return EOK;
00413 }
00414 
00428 int usb_pipe_control_read(usb_pipe_t *pipe,
00429     void *setup_buffer, size_t setup_buffer_size,
00430     void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
00431 {
00432         assert(pipe);
00433 
00434         if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
00435                 return EINVAL;
00436         }
00437 
00438         if ((data_buffer == NULL) || (data_buffer_size == 0)) {
00439                 return EINVAL;
00440         }
00441 
00442         if ((pipe->direction != USB_DIRECTION_BOTH)
00443             || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
00444                 return EBADF;
00445         }
00446 
00447         int rc;
00448 
00449         rc = pipe_add_ref(pipe, false);
00450         if (rc != EOK) {
00451                 return rc;
00452         }
00453 
00454         size_t act_size = 0;
00455         rc = usb_pipe_control_read_no_check(pipe,
00456             setup_buffer, setup_buffer_size,
00457             data_buffer, data_buffer_size, &act_size);
00458 
00459         if (rc == ESTALL) {
00460                 clear_self_endpoint_halt(pipe);
00461         }
00462 
00463         pipe_drop_ref(pipe);
00464 
00465         if (rc != EOK) {
00466                 return rc;
00467         }
00468 
00469         if (data_transfered_size != NULL) {
00470                 *data_transfered_size = act_size;
00471         }
00472 
00473         return EOK;
00474 }
00475 
00476 
00486 static int usb_pipe_control_write_no_check(usb_pipe_t *pipe,
00487     void *setup_buffer, size_t setup_buffer_size,
00488     void *data_buffer, size_t data_buffer_size)
00489 {
00490         /* Ensure serialization over the phone. */
00491         pipe_start_transaction(pipe);
00492 
00493         /*
00494          * Make call identifying target USB device and control transfer type.
00495          */
00496         aid_t opening_request = async_send_4(pipe->hc_phone,
00497             DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_CONTROL_WRITE,
00498             pipe->wire->address, pipe->endpoint_no,
00499             data_buffer_size,
00500             NULL);
00501         if (opening_request == 0) {
00502                 pipe_end_transaction(pipe);
00503                 return ENOMEM;
00504         }
00505 
00506         /*
00507          * Send the setup packet.
00508          */
00509         int rc = async_data_write_start(pipe->hc_phone,
00510             setup_buffer, setup_buffer_size);
00511         if (rc != EOK) {
00512                 pipe_end_transaction(pipe);
00513                 async_wait_for(opening_request, NULL);
00514                 return rc;
00515         }
00516 
00517         /*
00518          * Send the data (if any).
00519          */
00520         if (data_buffer_size > 0) {
00521                 rc = async_data_write_start(pipe->hc_phone,
00522                     data_buffer, data_buffer_size);
00523 
00524                 /* All data sent, pipe can be released. */
00525                 pipe_end_transaction(pipe);
00526 
00527                 if (rc != EOK) {
00528                         async_wait_for(opening_request, NULL);
00529                         return rc;
00530                 }
00531         } else {
00532                 /* No data to send, we can release the pipe for others. */
00533                 pipe_end_transaction(pipe);
00534         }
00535 
00536         /*
00537          * Wait for the answer.
00538          */
00539         sysarg_t opening_request_rc;
00540         async_wait_for(opening_request, &opening_request_rc);
00541 
00542         return (int) opening_request_rc;
00543 }
00544 
00556 int usb_pipe_control_write(usb_pipe_t *pipe,
00557     void *setup_buffer, size_t setup_buffer_size,
00558     void *data_buffer, size_t data_buffer_size)
00559 {
00560         assert(pipe);
00561 
00562         if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
00563                 return EINVAL;
00564         }
00565 
00566         if ((data_buffer == NULL) && (data_buffer_size > 0)) {
00567                 return EINVAL;
00568         }
00569 
00570         if ((data_buffer != NULL) && (data_buffer_size == 0)) {
00571                 return EINVAL;
00572         }
00573 
00574         if ((pipe->direction != USB_DIRECTION_BOTH)
00575             || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
00576                 return EBADF;
00577         }
00578 
00579         int rc;
00580 
00581         rc = pipe_add_ref(pipe, false);
00582         if (rc != EOK) {
00583                 return rc;
00584         }
00585 
00586         rc = usb_pipe_control_write_no_check(pipe,
00587             setup_buffer, setup_buffer_size, data_buffer, data_buffer_size);
00588 
00589         if (rc == ESTALL) {
00590                 clear_self_endpoint_halt(pipe);
00591         }
00592 
00593         pipe_drop_ref(pipe);
00594 
00595         return rc;
00596 }
00597 
00598 

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