Ignore:
File:
1 edited

Legend:

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

    r56bdd9a4 r47dfb34  
    11/*
    22 * Copyright (c) 2011 Vojtech Horky
     3 * Copyright (c) 2011 Jan Vesely
    34 * All rights reserved.
    45 *
     
    2627 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2728 */
    28 
    2929/** @addtogroup libusbdev
    3030 * @{
     
    3333 * USB endpoint pipes miscellaneous functions.
    3434 */
    35 #include <usb/usb.h>
     35#include <usb_iface.h>
    3636#include <usb/dev/pipes.h>
    37 #include <usb/debug.h>
    38 #include <usb/hc.h>
    39 #include <usbhc_iface.h>
    40 #include <usb_iface.h>
    41 #include <devman.h>
     37#include <usb/dev/request.h>
    4238#include <errno.h>
    4339#include <assert.h>
    44 #include "pipepriv.h"
    45 
    46 #define IPC_AGAIN_DELAY (1000 * 2) /* 2ms */
    47 
    48 /** Tell USB address assigned to given device.
    49  *
    50  * @param sess Session to parent device.
    51  * @param dev Device in question.
    52  * @return USB address or error code.
    53  */
    54 static usb_address_t get_my_address(async_sess_t *sess, const ddf_dev_t *dev)
    55 {
    56         assert(sess);
    57         async_exch_t *exch = async_exchange_begin(sess);
    58         if (!exch)
    59                 return ENOMEM;
    60 
    61         usb_address_t address;
    62         const int ret = usb_get_my_address(exch, &address);
    63 
    64         async_exchange_end(exch);
    65 
    66         return (ret == EOK) ? address : ret;
    67 }
    6840
    6941/** Tell USB interface assigned to given device.
     
    9264        return ret == EOK ? iface_no : ret;
    9365}
    94 
    95 /** Initialize connection to USB device.
    96  *
    97  * @param connection Connection structure to be initialized.
    98  * @param dev Generic device backing the USB device.
    99  * @return Error code.
    100  */
    101 int usb_device_connection_initialize_from_device(
    102     usb_device_connection_t *connection, const ddf_dev_t *dev)
    103 {
    104         assert(connection);
    105         assert(dev);
    106        
    107         int rc;
    108         devman_handle_t hc_handle;
    109         usb_address_t my_address;
    110        
    111         rc = usb_hc_find(dev->handle, &hc_handle);
    112         if (rc != EOK)
    113                 return rc;
    114        
    115         async_sess_t *parent_sess =
    116             devman_parent_device_connect(EXCHANGE_ATOMIC, dev->handle,
    117             IPC_FLAG_BLOCKING);
    118         if (!parent_sess)
    119                 return ENOMEM;
    120        
    121         /*
    122          * Asking for "my" address may require several attempts.
    123          * That is because following scenario may happen:
    124          *  - parent driver (i.e. driver of parent device) announces new device
    125          *    and devman launches current driver
    126          *  - parent driver is preempted and thus does not send address-handle
    127          *    binding to HC driver
    128          *  - this driver gets here and wants the binding
    129          *  - the HC does not know the binding yet and thus it answers ENOENT
    130          *  So, we need to wait for the HC to learn the binding.
    131          */
    132        
    133         do {
    134                 my_address = get_my_address(parent_sess, dev);
    135                
    136                 if (my_address == ENOENT) {
    137                         /* Be nice, let other fibrils run and try again. */
    138                         async_usleep(IPC_AGAIN_DELAY);
    139                 } else if (my_address < 0) {
    140                         /* Some other problem, no sense trying again. */
    141                         rc = my_address;
    142                         goto leave;
    143                 }
    144        
    145         } while (my_address < 0);
    146        
    147         rc = usb_device_connection_initialize(connection,
    148             hc_handle, my_address);
    149        
    150 leave:
    151         async_hangup(parent_sess);
    152         return rc;
    153 }
    154 
    155 /** Initialize connection to USB device.
    156  *
    157  * @param connection Connection structure to be initialized.
    158  * @param host_controller_handle Devman handle of host controller device is
    159  *      connected to.
    160  * @param device_address Device USB address.
    161  * @return Error code.
    162  */
    163 int usb_device_connection_initialize(usb_device_connection_t *connection,
    164     devman_handle_t host_controller_handle, usb_address_t device_address)
    165 {
    166         assert(connection);
    167 
    168         if ((device_address < 0) || (device_address >= USB11_ADDRESS_MAX)) {
    169                 return EINVAL;
    170         }
    171 
    172         connection->hc_handle = host_controller_handle;
    173         connection->address = device_address;
    174 
    175         return EOK;
    176 }
    177 
    178 /** Initialize connection to USB device on default address.
    179  *
    180  * @param dev_connection Device connection structure to be initialized.
    181  * @param hc_connection Initialized connection to host controller.
    182  * @return Error code.
    183  */
    184 int usb_device_connection_initialize_on_default_address(
    185     usb_device_connection_t *dev_connection,
    186     usb_hc_connection_t *hc_connection)
    187 {
    188         assert(dev_connection);
    189 
    190         if (hc_connection == NULL) {
    191                 return EBADMEM;
    192         }
    193 
    194         return usb_device_connection_initialize(dev_connection,
    195             hc_connection->hc_handle, (usb_address_t) 0);
    196 }
    197 
     66/*----------------------------------------------------------------------------*/
    19867/** Prepare pipe for a long transfer.
    19968 *
     
    20675 * @return Error code.
    20776 */
    208 void usb_pipe_start_long_transfer(usb_pipe_t *pipe)
    209 {
    210         (void) pipe_add_ref(pipe, true);
    211 }
    212 
     77int usb_pipe_start_long_transfer(usb_pipe_t *pipe)
     78{
     79        assert(pipe);
     80        assert(pipe->wire);
     81        assert(pipe->wire->hc_connection);
     82        return usb_hc_connection_open(pipe->wire->hc_connection);
     83}
     84/*----------------------------------------------------------------------------*/
    21385/** Terminate a long transfer on a pipe.
    21486 *
     
    21789 * @param pipe Pipe where to end the long transfer.
    21890 */
    219 void usb_pipe_end_long_transfer(usb_pipe_t *pipe)
    220 {
    221         pipe_drop_ref(pipe);
    222 }
    223 
     91int usb_pipe_end_long_transfer(usb_pipe_t *pipe)
     92{
     93        assert(pipe);
     94        assert(pipe->wire);
     95        assert(pipe->wire->hc_connection);
     96        return usb_hc_connection_close(pipe->wire->hc_connection);
     97}
     98/*----------------------------------------------------------------------------*/
     99/** Request an in transfer, no checking of input parameters.
     100 *
     101 * @param[in] pipe Pipe used for the transfer.
     102 * @param[out] buffer Buffer where to store the data.
     103 * @param[in] size Size of the buffer (in bytes).
     104 * @param[out] size_transfered Number of bytes that were actually transfered.
     105 * @return Error code.
     106 */
     107static int usb_pipe_read_no_check(usb_pipe_t *pipe, uint64_t setup,
     108    void *buffer, size_t size, size_t *size_transfered)
     109{
     110        /* Isochronous transfer are not supported (yet) */
     111        if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
     112            pipe->transfer_type != USB_TRANSFER_BULK &&
     113            pipe->transfer_type != USB_TRANSFER_CONTROL)
     114            return ENOTSUP;
     115
     116        return usb_hc_control_read(pipe->wire->hc_connection,
     117            pipe->wire->address, pipe->endpoint_no, setup, buffer, size,
     118            size_transfered);
     119}
     120/*----------------------------------------------------------------------------*/
     121/** Request an out transfer, no checking of input parameters.
     122 *
     123 * @param[in] pipe Pipe used for the transfer.
     124 * @param[in] buffer Buffer with data to transfer.
     125 * @param[in] size Size of the buffer (in bytes).
     126 * @return Error code.
     127 */
     128static int usb_pipe_write_no_check(usb_pipe_t *pipe, uint64_t setup,
     129    const void *buffer, size_t size)
     130{
     131        /* Only interrupt and bulk transfers are supported */
     132        if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
     133            pipe->transfer_type != USB_TRANSFER_BULK &&
     134            pipe->transfer_type != USB_TRANSFER_CONTROL)
     135            return ENOTSUP;
     136
     137        return usb_hc_control_write(pipe->wire->hc_connection,
     138            pipe->wire->address, pipe->endpoint_no, setup, buffer, size);
     139}
     140/*----------------------------------------------------------------------------*/
     141/** Try to clear endpoint halt of default control pipe.
     142 *
     143 * @param pipe Pipe for control endpoint zero.
     144 */
     145static void clear_self_endpoint_halt(usb_pipe_t *pipe)
     146{
     147        assert(pipe != NULL);
     148
     149        if (!pipe->auto_reset_halt || (pipe->endpoint_no != 0)) {
     150                return;
     151        }
     152
     153
     154        /* Prevent infinite recursion. */
     155        pipe->auto_reset_halt = false;
     156        usb_request_clear_endpoint_halt(pipe, 0);
     157        pipe->auto_reset_halt = true;
     158}
     159/*----------------------------------------------------------------------------*/
     160/** Request a control read transfer on an endpoint pipe.
     161 *
     162 * This function encapsulates all three stages of a control transfer.
     163 *
     164 * @param[in] pipe Pipe used for the transfer.
     165 * @param[in] setup_buffer Buffer with the setup packet.
     166 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
     167 * @param[out] data_buffer Buffer for incoming data.
     168 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
     169 * @param[out] data_transfered_size Number of bytes that were actually
     170 *                                  transfered during the DATA stage.
     171 * @return Error code.
     172 */
     173int usb_pipe_control_read(usb_pipe_t *pipe,
     174    const void *setup_buffer, size_t setup_buffer_size,
     175    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
     176{
     177        assert(pipe);
     178
     179        if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
     180                return EINVAL;
     181        }
     182
     183        if ((data_buffer == NULL) || (data_buffer_size == 0)) {
     184                return EINVAL;
     185        }
     186
     187        if ((pipe->direction != USB_DIRECTION_BOTH)
     188            || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
     189                return EBADF;
     190        }
     191
     192        uint64_t setup_packet;
     193        memcpy(&setup_packet, setup_buffer, 8);
     194
     195        size_t act_size = 0;
     196        const int rc = usb_pipe_read_no_check(pipe, setup_packet,
     197            data_buffer, data_buffer_size, &act_size);
     198
     199        if (rc == ESTALL) {
     200                clear_self_endpoint_halt(pipe);
     201        }
     202
     203        if (rc == EOK && data_transfered_size != NULL) {
     204                *data_transfered_size = act_size;
     205        }
     206
     207        return rc;
     208}
     209/*----------------------------------------------------------------------------*/
     210/** Request a control write transfer on an endpoint pipe.
     211 *
     212 * This function encapsulates all three stages of a control transfer.
     213 *
     214 * @param[in] pipe Pipe used for the transfer.
     215 * @param[in] setup_buffer Buffer with the setup packet.
     216 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
     217 * @param[in] data_buffer Buffer with data to be sent.
     218 * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
     219 * @return Error code.
     220 */
     221int usb_pipe_control_write(usb_pipe_t *pipe,
     222    const void *setup_buffer, size_t setup_buffer_size,
     223    const void *data_buffer, size_t data_buffer_size)
     224{
     225        assert(pipe);
     226
     227        if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
     228                return EINVAL;
     229        }
     230
     231        if ((data_buffer == NULL) && (data_buffer_size > 0)) {
     232                return EINVAL;
     233        }
     234
     235        if ((data_buffer != NULL) && (data_buffer_size == 0)) {
     236                return EINVAL;
     237        }
     238
     239        if ((pipe->direction != USB_DIRECTION_BOTH)
     240            || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
     241                return EBADF;
     242        }
     243
     244        uint64_t setup_packet;
     245        memcpy(&setup_packet, setup_buffer, 8);
     246
     247        const int rc = usb_pipe_write_no_check(pipe, setup_packet,
     248            data_buffer, data_buffer_size);
     249
     250        if (rc == ESTALL) {
     251                clear_self_endpoint_halt(pipe);
     252        }
     253
     254        return rc;
     255}
     256/*----------------------------------------------------------------------------*/
     257/** Request a read (in) transfer on an endpoint pipe.
     258 *
     259 * @param[in] pipe Pipe used for the transfer.
     260 * @param[out] buffer Buffer where to store the data.
     261 * @param[in] size Size of the buffer (in bytes).
     262 * @param[out] size_transfered Number of bytes that were actually transfered.
     263 * @return Error code.
     264 */
     265int usb_pipe_read(usb_pipe_t *pipe,
     266    void *buffer, size_t size, size_t *size_transfered)
     267{
     268        assert(pipe);
     269
     270        if (buffer == NULL) {
     271                return EINVAL;
     272        }
     273
     274        if (size == 0) {
     275                return EINVAL;
     276        }
     277
     278        if (pipe->direction != USB_DIRECTION_IN) {
     279                return EBADF;
     280        }
     281
     282        if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
     283                return EBADF;
     284        }
     285
     286        size_t act_size = 0;
     287        const int rc = usb_pipe_read_no_check(pipe, 0, buffer, size, &act_size);
     288
     289
     290        if (rc == EOK && size_transfered != NULL) {
     291                *size_transfered = act_size;
     292        }
     293
     294        return rc;
     295}
     296/*----------------------------------------------------------------------------*/
     297/** Request a write (out) transfer on an endpoint pipe.
     298 *
     299 * @param[in] pipe Pipe used for the transfer.
     300 * @param[in] buffer Buffer with data to transfer.
     301 * @param[in] size Size of the buffer (in bytes).
     302 * @return Error code.
     303 */
     304int usb_pipe_write(usb_pipe_t *pipe, const void *buffer, size_t size)
     305{
     306        assert(pipe);
     307
     308        if (buffer == NULL || size == 0) {
     309                return EINVAL;
     310        }
     311
     312        if (pipe->direction != USB_DIRECTION_OUT) {
     313                return EBADF;
     314        }
     315
     316        if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
     317                return EBADF;
     318        }
     319
     320        return usb_pipe_write_no_check(pipe, 0, buffer, size);
     321}
    224322/**
    225323 * @}
Note: See TracChangeset for help on using the changeset viewer.