Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usbdev/src/pipesio.c

    r3f0ad85a r3875af65  
    6262 * @return Error code.
    6363 */
    64 static int usb_pipe_read_no_check(usb_pipe_t *pipe, uint64_t setup,
     64static int usb_pipe_read_no_checks(usb_pipe_t *pipe,
    6565    void *buffer, size_t size, size_t *size_transfered)
    6666{
    67         /* Isochronous transfer are not supported (yet) */
     67        /* Only interrupt and bulk transfers are supported */
    6868        if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
    69             pipe->transfer_type != USB_TRANSFER_BULK &&
    70             pipe->transfer_type != USB_TRANSFER_CONTROL)
     69            pipe->transfer_type != USB_TRANSFER_BULK)
    7170            return ENOTSUP;
    7271
    73         int ret = pipe_add_ref(pipe, false);
    74         if (ret != EOK) {
    75                 return ret;
    76         }
    77 
     72        const usb_target_t target =
     73            {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
     74       
    7875        /* Ensure serialization over the phone. */
    7976        pipe_start_transaction(pipe);
    8077        async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
    81         if (!exch) {
     78       
     79        /*
     80         * Make call identifying target USB device and type of transfer.
     81         */
     82        aid_t opening_request = async_send_2(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
     83            IPC_M_USBHC_READ, target.packed, NULL);
     84       
     85        if (opening_request == 0) {
     86                async_exchange_end(exch);
    8287                pipe_end_transaction(pipe);
    83                 pipe_drop_ref(pipe);
    8488                return ENOMEM;
    8589        }
    86 
    87         ret = usbhc_read(exch, pipe->wire->address, pipe->endpoint_no,
    88             setup, buffer, size, size_transfered);
     90       
     91        /*
     92         * Retrieve the data.
     93         */
     94        ipc_call_t data_request_call;
     95        aid_t data_request = async_data_read(exch, buffer, size,
     96            &data_request_call);
     97       
     98        /*
     99         * Since now on, someone else might access the backing phone
     100         * without breaking the transfer IPC protocol.
     101         */
    89102        async_exchange_end(exch);
    90103        pipe_end_transaction(pipe);
     104       
     105        if (data_request == 0) {
     106                /*
     107                 * FIXME:
     108                 * How to let the other side know that we want to abort?
     109                 */
     110                async_wait_for(opening_request, NULL);
     111                return ENOMEM;
     112        }
     113       
     114        /*
     115         * Wait for the answer.
     116         */
     117        sysarg_t data_request_rc;
     118        sysarg_t opening_request_rc;
     119        async_wait_for(data_request, &data_request_rc);
     120        async_wait_for(opening_request, &opening_request_rc);
     121       
     122        if (data_request_rc != EOK) {
     123                /* Prefer the return code of the opening request. */
     124                if (opening_request_rc != EOK) {
     125                        return (int) opening_request_rc;
     126                } else {
     127                        return (int) data_request_rc;
     128                }
     129        }
     130        if (opening_request_rc != EOK) {
     131                return (int) opening_request_rc;
     132        }
     133       
     134        *size_transfered = IPC_GET_ARG2(data_request_call);
     135       
     136        return EOK;
     137}
     138
     139
     140/** Request a read (in) transfer on an endpoint pipe.
     141 *
     142 * @param[in] pipe Pipe used for the transfer.
     143 * @param[out] buffer Buffer where to store the data.
     144 * @param[in] size Size of the buffer (in bytes).
     145 * @param[out] size_transfered Number of bytes that were actually transfered.
     146 * @return Error code.
     147 */
     148int usb_pipe_read(usb_pipe_t *pipe,
     149    void *buffer, size_t size, size_t *size_transfered)
     150{
     151        assert(pipe);
     152
     153        if (buffer == NULL) {
     154                return EINVAL;
     155        }
     156
     157        if (size == 0) {
     158                return EINVAL;
     159        }
     160
     161        if (pipe->direction != USB_DIRECTION_IN) {
     162                return EBADF;
     163        }
     164
     165        if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
     166                return EBADF;
     167        }
     168
     169        int rc;
     170        rc = pipe_add_ref(pipe, false);
     171        if (rc != EOK) {
     172                return rc;
     173        }
     174
     175
     176        size_t act_size = 0;
     177
     178        rc = usb_pipe_read_no_checks(pipe, buffer, size, &act_size);
     179
    91180        pipe_drop_ref(pipe);
    92         return ret;
    93 }
     181
     182        if (rc != EOK) {
     183                return rc;
     184        }
     185
     186        if (size_transfered != NULL) {
     187                *size_transfered = act_size;
     188        }
     189
     190        return EOK;
     191}
     192
     193
     194
    94195
    95196/** Request an out transfer, no checking of input parameters.
     
    100201 * @return Error code.
    101202 */
    102 static int usb_pipe_write_no_check(usb_pipe_t *pipe, uint64_t setup,
    103     const void *buffer, size_t size)
     203static int usb_pipe_write_no_check(usb_pipe_t *pipe,
     204    void *buffer, size_t size)
    104205{
    105206        /* Only interrupt and bulk transfers are supported */
    106207        if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
    107             pipe->transfer_type != USB_TRANSFER_BULK &&
    108             pipe->transfer_type != USB_TRANSFER_CONTROL)
     208            pipe->transfer_type != USB_TRANSFER_BULK)
    109209            return ENOTSUP;
    110210
    111         int ret = pipe_add_ref(pipe, false);
    112         if (ret != EOK) {
    113                 return ret;
    114         }
     211        const usb_target_t target =
     212            {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
    115213
    116214        /* Ensure serialization over the phone. */
    117215        pipe_start_transaction(pipe);
    118216        async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
    119         if (!exch) {
     217       
     218        /*
     219         * Make call identifying target USB device and type of transfer.
     220         */
     221        aid_t opening_request = async_send_3(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
     222            IPC_M_USBHC_WRITE, target.packed, size, NULL);
     223       
     224        if (opening_request == 0) {
     225                async_exchange_end(exch);
    120226                pipe_end_transaction(pipe);
    121                 pipe_drop_ref(pipe);
    122227                return ENOMEM;
    123228        }
    124         ret = usbhc_write(exch, pipe->wire->address, pipe->endpoint_no,
    125             setup, buffer, size);
     229       
     230        /*
     231         * Send the data.
     232         */
     233        int rc = async_data_write_start(exch, buffer, size);
     234       
     235        /*
     236         * Since now on, someone else might access the backing phone
     237         * without breaking the transfer IPC protocol.
     238         */
    126239        async_exchange_end(exch);
    127240        pipe_end_transaction(pipe);
     241       
     242        if (rc != EOK) {
     243                async_wait_for(opening_request, NULL);
     244                return rc;
     245        }
     246       
     247        /*
     248         * Wait for the answer.
     249         */
     250        sysarg_t opening_request_rc;
     251        async_wait_for(opening_request, &opening_request_rc);
     252       
     253        return (int) opening_request_rc;
     254}
     255
     256/** Request a write (out) transfer on an endpoint pipe.
     257 *
     258 * @param[in] pipe Pipe used for the transfer.
     259 * @param[in] buffer Buffer with data to transfer.
     260 * @param[in] size Size of the buffer (in bytes).
     261 * @return Error code.
     262 */
     263int usb_pipe_write(usb_pipe_t *pipe,
     264    void *buffer, size_t size)
     265{
     266        assert(pipe);
     267
     268        if (buffer == NULL) {
     269                return EINVAL;
     270        }
     271
     272        if (size == 0) {
     273                return EINVAL;
     274        }
     275
     276        if (pipe->direction != USB_DIRECTION_OUT) {
     277                return EBADF;
     278        }
     279
     280        if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
     281                return EBADF;
     282        }
     283
     284        int rc;
     285
     286        rc = pipe_add_ref(pipe, false);
     287        if (rc != EOK) {
     288                return rc;
     289        }
     290
     291        rc = usb_pipe_write_no_check(pipe, buffer, size);
     292
    128293        pipe_drop_ref(pipe);
    129         return ret;
     294
     295        return rc;
    130296}
    131297
     
    143309
    144310
    145         /* Prevent infinite recursion. */
     311        /* Prevent indefinite recursion. */
    146312        pipe->auto_reset_halt = false;
    147313        usb_request_clear_endpoint_halt(pipe, 0);
     
    149315}
    150316
    151 /** Request a control read transfer on an endpoint pipe.
    152  *
    153  * This function encapsulates all three stages of a control transfer.
     317
     318/** Request a control read transfer, no checking of input parameters.
    154319 *
    155320 * @param[in] pipe Pipe used for the transfer.
     
    162327 * @return Error code.
    163328 */
     329static int usb_pipe_control_read_no_check(usb_pipe_t *pipe,
     330    const void *setup_buffer, size_t setup_buffer_size,
     331    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
     332{
     333        /* Ensure serialization over the phone. */
     334        pipe_start_transaction(pipe);
     335
     336        const usb_target_t target =
     337            {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
     338
     339        assert(setup_buffer_size == 8);
     340        uint64_t setup_packet;
     341        memcpy(&setup_packet, setup_buffer, 8);
     342        /*
     343         * Make call identifying target USB device and control transfer type.
     344         */
     345        async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
     346        aid_t opening_request = async_send_4(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
     347            IPC_M_USBHC_READ, target.packed,
     348            (setup_packet & UINT32_MAX), (setup_packet >> 32), NULL);
     349
     350        if (opening_request == 0) {
     351                async_exchange_end(exch);
     352                return ENOMEM;
     353        }
     354
     355        /*
     356         * Retrieve the data.
     357         */
     358        ipc_call_t data_request_call;
     359        aid_t data_request = async_data_read(exch, data_buffer,
     360            data_buffer_size, &data_request_call);
     361       
     362        /*
     363         * Since now on, someone else might access the backing phone
     364         * without breaking the transfer IPC protocol.
     365         */
     366        async_exchange_end(exch);
     367        pipe_end_transaction(pipe);
     368       
     369        if (data_request == 0) {
     370                async_wait_for(opening_request, NULL);
     371                return ENOMEM;
     372        }
     373
     374        /*
     375         * Wait for the answer.
     376         */
     377        sysarg_t data_request_rc;
     378        sysarg_t opening_request_rc;
     379        async_wait_for(data_request, &data_request_rc);
     380        async_wait_for(opening_request, &opening_request_rc);
     381
     382        if (data_request_rc != EOK) {
     383                /* Prefer the return code of the opening request. */
     384                if (opening_request_rc != EOK) {
     385                        return (int) opening_request_rc;
     386                } else {
     387                        return (int) data_request_rc;
     388                }
     389        }
     390        if (opening_request_rc != EOK) {
     391                return (int) opening_request_rc;
     392        }
     393
     394        *data_transfered_size = IPC_GET_ARG2(data_request_call);
     395
     396        return EOK;
     397}
     398
     399/** Request a control read transfer on an endpoint pipe.
     400 *
     401 * This function encapsulates all three stages of a control transfer.
     402 *
     403 * @param[in] pipe Pipe used for the transfer.
     404 * @param[in] setup_buffer Buffer with the setup packet.
     405 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
     406 * @param[out] data_buffer Buffer for incoming data.
     407 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
     408 * @param[out] data_transfered_size Number of bytes that were actually
     409 *                                  transfered during the DATA stage.
     410 * @return Error code.
     411 */
    164412int usb_pipe_control_read(usb_pipe_t *pipe,
    165413    const void *setup_buffer, size_t setup_buffer_size,
     
    168416        assert(pipe);
    169417
    170         if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
     418        if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
    171419                return EINVAL;
    172420        }
     
    181429        }
    182430
    183         uint64_t setup_packet;
    184         memcpy(&setup_packet, setup_buffer, 8);
     431        int rc;
     432
     433        rc = pipe_add_ref(pipe, false);
     434        if (rc != EOK) {
     435                return rc;
     436        }
    185437
    186438        size_t act_size = 0;
    187         const int rc = usb_pipe_read_no_check(pipe, setup_packet,
     439        rc = usb_pipe_control_read_no_check(pipe,
     440            setup_buffer, setup_buffer_size,
    188441            data_buffer, data_buffer_size, &act_size);
    189442
     
    192445        }
    193446
    194         if (rc == EOK && data_transfered_size != NULL) {
     447        pipe_drop_ref(pipe);
     448
     449        if (rc != EOK) {
     450                return rc;
     451        }
     452
     453        if (data_transfered_size != NULL) {
    195454                *data_transfered_size = act_size;
    196455        }
    197456
    198         return rc;
    199 }
    200 
    201 /** Request a control write transfer on an endpoint pipe.
    202  *
    203  * This function encapsulates all three stages of a control transfer.
     457        return EOK;
     458}
     459
     460
     461/** Request a control write transfer, no checking of input parameters.
    204462 *
    205463 * @param[in] pipe Pipe used for the transfer.
     
    210468 * @return Error code.
    211469 */
     470static int usb_pipe_control_write_no_check(usb_pipe_t *pipe,
     471    const void *setup_buffer, size_t setup_buffer_size,
     472    const void *data_buffer, size_t data_buffer_size)
     473{
     474        /* Ensure serialization over the phone. */
     475        pipe_start_transaction(pipe);
     476
     477        const usb_target_t target =
     478            {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
     479        assert(setup_buffer_size == 8);
     480        uint64_t setup_packet;
     481        memcpy(&setup_packet, setup_buffer, 8);
     482
     483        /*
     484         * Make call identifying target USB device and control transfer type.
     485         */
     486        async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
     487        aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
     488            IPC_M_USBHC_WRITE, target.packed, data_buffer_size,
     489            (setup_packet & UINT32_MAX), (setup_packet >> 32), NULL);
     490       
     491        if (opening_request == 0) {
     492                async_exchange_end(exch);
     493                pipe_end_transaction(pipe);
     494                return ENOMEM;
     495        }
     496
     497        /*
     498         * Send the data (if any).
     499         */
     500        if (data_buffer_size > 0) {
     501                int rc = async_data_write_start(exch, data_buffer, data_buffer_size);
     502               
     503                /* All data sent, pipe can be released. */
     504                async_exchange_end(exch);
     505                pipe_end_transaction(pipe);
     506       
     507                if (rc != EOK) {
     508                        async_wait_for(opening_request, NULL);
     509                        return rc;
     510                }
     511        } else {
     512                /* No data to send, we can release the pipe for others. */
     513                async_exchange_end(exch);
     514                pipe_end_transaction(pipe);
     515        }
     516       
     517        /*
     518         * Wait for the answer.
     519         */
     520        sysarg_t opening_request_rc;
     521        async_wait_for(opening_request, &opening_request_rc);
     522
     523        return (int) opening_request_rc;
     524}
     525
     526/** Request a control write transfer on an endpoint pipe.
     527 *
     528 * This function encapsulates all three stages of a control transfer.
     529 *
     530 * @param[in] pipe Pipe used for the transfer.
     531 * @param[in] setup_buffer Buffer with the setup packet.
     532 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
     533 * @param[in] data_buffer Buffer with data to be sent.
     534 * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
     535 * @return Error code.
     536 */
    212537int usb_pipe_control_write(usb_pipe_t *pipe,
    213538    const void *setup_buffer, size_t setup_buffer_size,
     
    216541        assert(pipe);
    217542
    218         if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
     543        if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
    219544                return EINVAL;
    220545        }
     
    233558        }
    234559
    235         uint64_t setup_packet;
    236         memcpy(&setup_packet, setup_buffer, 8);
    237 
    238         const int rc = usb_pipe_write_no_check(pipe, setup_packet,
    239             data_buffer, data_buffer_size);
     560        int rc;
     561
     562        rc = pipe_add_ref(pipe, false);
     563        if (rc != EOK) {
     564                return rc;
     565        }
     566
     567        rc = usb_pipe_control_write_no_check(pipe,
     568            setup_buffer, setup_buffer_size, data_buffer, data_buffer_size);
    240569
    241570        if (rc == ESTALL) {
     
    243572        }
    244573
     574        pipe_drop_ref(pipe);
     575
    245576        return rc;
    246577}
    247578
    248 /** Request a read (in) transfer on an endpoint pipe.
    249  *
    250  * @param[in] pipe Pipe used for the transfer.
    251  * @param[out] buffer Buffer where to store the data.
    252  * @param[in] size Size of the buffer (in bytes).
    253  * @param[out] size_transfered Number of bytes that were actually transfered.
    254  * @return Error code.
    255  */
    256 int usb_pipe_read(usb_pipe_t *pipe,
    257     void *buffer, size_t size, size_t *size_transfered)
    258 {
    259         assert(pipe);
    260 
    261         if (buffer == NULL) {
    262                 return EINVAL;
    263         }
    264 
    265         if (size == 0) {
    266                 return EINVAL;
    267         }
    268 
    269         if (pipe->direction != USB_DIRECTION_IN) {
    270                 return EBADF;
    271         }
    272 
    273         if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
    274                 return EBADF;
    275         }
    276 
    277         size_t act_size = 0;
    278         const int rc = usb_pipe_read_no_check(pipe, 0, buffer, size, &act_size);
    279 
    280 
    281         if (rc == EOK && size_transfered != NULL) {
    282                 *size_transfered = act_size;
    283         }
    284 
    285         return rc;
    286 }
    287 
    288 /** Request a write (out) transfer on an endpoint pipe.
    289  *
    290  * @param[in] pipe Pipe used for the transfer.
    291  * @param[in] buffer Buffer with data to transfer.
    292  * @param[in] size Size of the buffer (in bytes).
    293  * @return Error code.
    294  */
    295 int usb_pipe_write(usb_pipe_t *pipe, const void *buffer, size_t size)
    296 {
    297         assert(pipe);
    298 
    299         if (buffer == NULL || size == 0) {
    300                 return EINVAL;
    301         }
    302 
    303         if (pipe->direction != USB_DIRECTION_OUT) {
    304                 return EBADF;
    305         }
    306 
    307         if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
    308                 return EBADF;
    309         }
    310 
    311         return usb_pipe_write_no_check(pipe, 0, buffer, size);
    312 }
    313579
    314580/**
Note: See TracChangeset for help on using the changeset viewer.