Ignore:
File:
1 edited

Legend:

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

    re773f58 rb7fd2a0  
    22 * Copyright (c) 2011 Vojtech Horky
    33 * Copyright (c) 2011 Jan Vesely
    4  * Copyright (c) 2018 Ondrej Hlavaty, Michal Staruch
    54 * All rights reserved.
    65 *
     
    3736#include <usb/dev/request.h>
    3837#include <usb/usb.h>
    39 #include <usb/dma_buffer.h>
     38#include <usb_iface.h>
    4039
    4140#include <assert.h>
    42 #include <bitops.h>
    4341#include <async.h>
    44 #include <as.h>
    4542#include <errno.h>
    4643#include <mem.h>
     
    5451        assert(pipe != NULL);
    5552
    56         if (!pipe->auto_reset_halt || (pipe->desc.endpoint_no != 0)) {
     53        if (!pipe->auto_reset_halt || (pipe->endpoint_no != 0)) {
    5754                return;
    5855        }
     
    6057        /* Prevent infinite recursion. */
    6158        pipe->auto_reset_halt = false;
    62         usb_pipe_clear_halt(pipe, pipe);
     59        usb_request_clear_endpoint_halt(pipe, 0);
    6360        pipe->auto_reset_halt = true;
    64 }
    65 
    66 /* Helper structure to avoid passing loads of arguments through */
    67 typedef struct {
    68         usb_pipe_t *pipe;
    69         usb_direction_t dir;
    70         bool is_control;        // Only for checking purposes
    71 
    72         usbhc_iface_transfer_request_t req;
    73 
    74         size_t transferred_size;
    75 } transfer_t;
    76 
    77 /**
    78  * Issue a transfer in a separate exchange.
    79  */
    80 static errno_t transfer_common(transfer_t *t)
    81 {
    82         if (!t->pipe)
    83                 return EBADMEM;
    84 
    85         /* Only control writes make sense without buffer */
    86         if ((t->dir != USB_DIRECTION_OUT || !t->is_control) && t->req.size == 0)
    87                 return EINVAL;
    88 
    89         /* Nonzero size requires buffer */
    90         if (!dma_buffer_is_set(&t->req.buffer) && t->req.size != 0)
    91                 return EINVAL;
    92 
    93         /* Check expected direction */
    94         if (t->pipe->desc.direction != USB_DIRECTION_BOTH &&
    95             t->pipe->desc.direction != t->dir)
    96                 return EBADF;
    97 
    98         /* Check expected transfer type */
    99         if ((t->pipe->desc.transfer_type == USB_TRANSFER_CONTROL) != t->is_control)
    100                 return EBADF;
    101 
    102         async_exch_t *exch = async_exchange_begin(t->pipe->bus_session);
    103         if (!exch)
    104                 return ENOMEM;
    105 
    106         t->req.dir = t->dir;
    107         t->req.endpoint = t->pipe->desc.endpoint_no;
    108 
    109         const errno_t rc = usbhc_transfer(exch, &t->req, &t->transferred_size);
    110 
    111         async_exchange_end(exch);
    112 
    113         if (rc == ESTALL)
    114                 clear_self_endpoint_halt(t->pipe);
    115 
    116         return rc;
    117 }
    118 
    119 /**
    120  * Setup the transfer request inside transfer according to dma buffer provided.
    121  *
    122  * TODO: The buffer could have been allocated as a more strict one. Currently,
    123  * we assume that the policy is just the requested one.
    124  */
    125 static void setup_dma_buffer(transfer_t *t, void *base, void *ptr, size_t size)
    126 {
    127         t->req.buffer.virt = base;
    128         t->req.buffer.policy = t->pipe->desc.transfer_buffer_policy;
    129         t->req.offset = ptr - base;
    130         t->req.size = size;
    131 }
    132 
    133 /**
    134  * Compatibility wrapper for reads/writes without preallocated buffer.
    135  */
    136 static errno_t transfer_wrap_dma(transfer_t *t, void *buf, size_t size)
    137 {
    138         if (size == 0) {
    139                 setup_dma_buffer(t, NULL, NULL, 0);
    140                 return transfer_common(t);
    141         }
    142 
    143         void *dma_buf = usb_pipe_alloc_buffer(t->pipe, size);
    144         setup_dma_buffer(t, dma_buf, dma_buf, size);
    145 
    146         if (t->dir == USB_DIRECTION_OUT)
    147                 memcpy(dma_buf, buf, size);
    148 
    149         const errno_t err = transfer_common(t);
    150 
    151         if (!err && t->dir == USB_DIRECTION_IN)
    152                 memcpy(buf, dma_buf, t->transferred_size);
    153 
    154         usb_pipe_free_buffer(t->pipe, dma_buf);
    155         return err;
    156 }
    157 
    158 static errno_t prepare_control(transfer_t *t, const void *setup, size_t setup_size)
    159 {
    160         if ((setup == NULL) || (setup_size != 8))
    161                 return EINVAL;
    162        
    163         memcpy(&t->req.setup, setup, 8);
    164         return EOK;
    16561}
    16662
     
    17470 * @param[out] data_buffer Buffer for incoming data.
    17571 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
    176  * @param[out] data_transferred_size Number of bytes that were actually
    177  *                                  transferred during the DATA stage.
     72 * @param[out] data_transfered_size Number of bytes that were actually
     73 *                                  transfered during the DATA stage.
    17874 * @return Error code.
    17975 */
    18076errno_t usb_pipe_control_read(usb_pipe_t *pipe,
    18177    const void *setup_buffer, size_t setup_buffer_size,
    182     void *buffer, size_t buffer_size, size_t *transferred_size)
    183 {
    184         errno_t err;
    185         transfer_t transfer = {
    186                 .pipe = pipe,
    187                 .dir = USB_DIRECTION_IN,
    188                 .is_control = true,
    189         };
    190 
    191         if ((err = prepare_control(&transfer, setup_buffer, setup_buffer_size)))
    192                 return err;
    193 
    194         if ((err = transfer_wrap_dma(&transfer, buffer, buffer_size)))
    195                 return err;
    196 
    197         if (transferred_size)
    198                 *transferred_size = transfer.transferred_size;
    199 
    200         return EOK;
     78    void *buffer, size_t buffer_size, size_t *transfered_size)
     79{
     80        assert(pipe);
     81
     82        if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
     83                return EINVAL;
     84        }
     85
     86        if ((buffer == NULL) || (buffer_size == 0)) {
     87                return EINVAL;
     88        }
     89
     90        if ((pipe->direction != USB_DIRECTION_BOTH)
     91            || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
     92                return EBADF;
     93        }
     94
     95        uint64_t setup_packet;
     96        memcpy(&setup_packet, setup_buffer, 8);
     97
     98        async_exch_t *exch = async_exchange_begin(pipe->bus_session);
     99        size_t act_size = 0;
     100        const errno_t rc = usb_read(exch, pipe->endpoint_no, setup_packet, buffer,
     101            buffer_size, &act_size);
     102        async_exchange_end(exch);
     103
     104        if (rc == ESTALL) {
     105                clear_self_endpoint_halt(pipe);
     106        }
     107
     108        if (rc == EOK && transfered_size != NULL) {
     109                *transfered_size = act_size;
     110        }
     111
     112        return rc;
    201113}
    202114
     
    217129{
    218130        assert(pipe);
    219         errno_t err;
    220         transfer_t transfer = {
    221                 .pipe = pipe,
    222                 .dir = USB_DIRECTION_OUT,
    223                 .is_control = true,
    224         };
    225 
    226         if ((err = prepare_control(&transfer, setup_buffer, setup_buffer_size)))
    227                 return err;
    228 
    229         return transfer_wrap_dma(&transfer, (void *) buffer, buffer_size);
    230 }
    231 
    232 /**
    233  * Allocate a buffer for data transmission, that satisfies the constraints
    234  * imposed by the host controller.
    235  *
    236  * @param[in] pipe Pipe for which the buffer is allocated
    237  * @param[in] size Size of the required buffer
    238  */
    239 void *usb_pipe_alloc_buffer(usb_pipe_t *pipe, size_t size)
    240 {
    241         dma_buffer_t buf;
    242         if (dma_buffer_alloc_policy(&buf, size, pipe->desc.transfer_buffer_policy))
    243                 return NULL;
    244 
    245         return buf.virt;
    246 }
    247 
    248 void usb_pipe_free_buffer(usb_pipe_t *pipe, void *buffer)
    249 {
    250         dma_buffer_t buf;
    251         buf.virt = buffer;
    252         dma_buffer_free(&buf);
     131
     132        if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
     133                return EINVAL;
     134        }
     135
     136        if ((buffer == NULL) && (buffer_size > 0)) {
     137                return EINVAL;
     138        }
     139
     140        if ((buffer != NULL) && (buffer_size == 0)) {
     141                return EINVAL;
     142        }
     143
     144        if ((pipe->direction != USB_DIRECTION_BOTH)
     145            || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
     146                return EBADF;
     147        }
     148
     149        uint64_t setup_packet;
     150        memcpy(&setup_packet, setup_buffer, 8);
     151
     152        async_exch_t *exch = async_exchange_begin(pipe->bus_session);
     153        const errno_t rc = usb_write(exch,
     154            pipe->endpoint_no, setup_packet, buffer, buffer_size);
     155        async_exchange_end(exch);
     156
     157        if (rc == ESTALL) {
     158                clear_self_endpoint_halt(pipe);
     159        }
     160
     161        return rc;
    253162}
    254163
     
    258167 * @param[out] buffer Buffer where to store the data.
    259168 * @param[in] size Size of the buffer (in bytes).
    260  * @param[out] size_transferred Number of bytes that were actually transferred.
     169 * @param[out] size_transfered Number of bytes that were actually transfered.
    261170 * @return Error code.
    262171 */
    263172errno_t usb_pipe_read(usb_pipe_t *pipe,
    264     void *buffer, size_t size, size_t *size_transferred)
    265 {
    266         assert(pipe);
    267         errno_t err;
    268         transfer_t transfer = {
    269                 .pipe = pipe,
    270                 .dir = USB_DIRECTION_IN,
    271         };
    272 
    273         if ((err = transfer_wrap_dma(&transfer, buffer, size)))
    274                 return err;
    275 
    276         if (size_transferred)
    277                 *size_transferred = transfer.transferred_size;
    278 
    279         return EOK;
     173    void *buffer, size_t size, size_t *size_transfered)
     174{
     175        assert(pipe);
     176
     177        if (buffer == NULL) {
     178                return EINVAL;
     179        }
     180
     181        if (size == 0) {
     182                return EINVAL;
     183        }
     184
     185        if (pipe->direction != USB_DIRECTION_IN) {
     186                return EBADF;
     187        }
     188
     189        if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
     190                return EBADF;
     191        }
     192
     193        /* Isochronous transfer are not supported (yet) */
     194        if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
     195            pipe->transfer_type != USB_TRANSFER_BULK)
     196            return ENOTSUP;
     197
     198        async_exch_t *exch = async_exchange_begin(pipe->bus_session);
     199        size_t act_size = 0;
     200        const errno_t rc =
     201            usb_read(exch, pipe->endpoint_no, 0, buffer, size, &act_size);
     202        async_exchange_end(exch);
     203
     204        if (rc == EOK && size_transfered != NULL) {
     205                *size_transfered = act_size;
     206        }
     207
     208        return rc;
    280209}
    281210
     
    290219{
    291220        assert(pipe);
    292         transfer_t transfer = {
    293                 .pipe = pipe,
    294                 .dir = USB_DIRECTION_OUT,
    295         };
    296 
    297         return transfer_wrap_dma(&transfer, (void *) buffer, size);
    298 }
    299 
    300 /**
    301  * Request a read (in) transfer on an endpoint pipe, declaring that buffer
    302  * is pointing to a memory area previously allocated by usb_pipe_alloc_buffer.
    303  *
    304  * @param[in] pipe Pipe used for the transfer.
    305  * @param[in] buffer Buffer, previously allocated with usb_pipe_alloc_buffer.
    306  * @param[in] size Size of the buffer (in bytes).
    307  * @param[out] size_transferred Number of bytes that were actually transferred.
    308  * @return Error code.
    309  */
    310 errno_t usb_pipe_read_dma(usb_pipe_t *pipe, void *base, void *ptr, size_t size,
    311     size_t *size_transferred)
    312 {
    313         assert(pipe);
    314         errno_t err;
    315         transfer_t transfer = {
    316                 .pipe = pipe,
    317                 .dir = USB_DIRECTION_IN,
    318         };
    319 
    320         setup_dma_buffer(&transfer, base, ptr, size);
    321 
    322         if ((err = transfer_common(&transfer)))
    323                 return err;
    324 
    325         if (size_transferred)
    326                 *size_transferred = transfer.transferred_size;
    327 
    328         return EOK;
    329 }
    330 
    331 /**
    332  * Request a write (out) transfer on an endpoint pipe, declaring that buffer
    333  * is pointing to a memory area previously allocated by usb_pipe_alloc_buffer.
    334  *
    335  * @param[in] pipe Pipe used for the transfer.
    336  * @param[in] buffer Buffer, previously allocated with usb_pipe_alloc_buffer.
    337  * @param[in] size Size of the buffer (in bytes).
    338  * @return Error code.
    339  */
    340 errno_t usb_pipe_write_dma(usb_pipe_t *pipe, void *base, void *ptr, size_t size)
    341 {
    342         assert(pipe);
    343         transfer_t transfer = {
    344                 .pipe = pipe,
    345                 .dir = USB_DIRECTION_OUT,
    346         };
    347 
    348         setup_dma_buffer(&transfer, base, ptr, size);
    349 
    350         return transfer_common(&transfer);
     221
     222        if (buffer == NULL || size == 0) {
     223                return EINVAL;
     224        }
     225
     226        if (pipe->direction != USB_DIRECTION_OUT) {
     227                return EBADF;
     228        }
     229
     230        if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
     231                return EBADF;
     232        }
     233
     234        /* Isochronous transfer are not supported (yet) */
     235        if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
     236            pipe->transfer_type != USB_TRANSFER_BULK)
     237            return ENOTSUP;
     238
     239        async_exch_t *exch = async_exchange_begin(pipe->bus_session);
     240        const errno_t rc = usb_write(exch, pipe->endpoint_no, 0, buffer, size);
     241        async_exchange_end(exch);
     242        return rc;
    351243}
    352244
     
    354246 *
    355247 * @param pipe Endpoint pipe to be initialized.
    356  * @param bus_session Endpoint pipe to be initialized.
    357  * @return Error code.
    358  */
    359 errno_t usb_pipe_initialize(usb_pipe_t *pipe, usb_dev_session_t *bus_session)
    360 {
    361         assert(pipe);
    362 
     248 * @param endpoint_no Endpoint number (in USB 1.1 in range 0 to 15).
     249 * @param transfer_type Transfer type (e.g. interrupt or bulk).
     250 * @param max_packet_size Maximum packet size in bytes.
     251 * @param direction Endpoint direction (in/out).
     252 * @return Error code.
     253 */
     254errno_t usb_pipe_initialize(usb_pipe_t *pipe, usb_endpoint_t endpoint_no,
     255    usb_transfer_type_t transfer_type, size_t max_packet_size,
     256    usb_direction_t direction, unsigned packets, usb_dev_session_t *bus_session)
     257{
     258        assert(pipe);
     259
     260        pipe->endpoint_no = endpoint_no;
     261        pipe->transfer_type = transfer_type;
     262        pipe->packets = packets;
     263        pipe->max_packet_size = max_packet_size;
     264        pipe->direction = direction;
    363265        pipe->auto_reset_halt = false;
    364266        pipe->bus_session = bus_session;
     
    367269}
    368270
    369 static const usb_pipe_desc_t default_control_pipe = {
    370         .endpoint_no = 0,
    371         .transfer_type = USB_TRANSFER_CONTROL,
    372         .direction = USB_DIRECTION_BOTH,
    373         .max_transfer_size = CTRL_PIPE_MIN_PACKET_SIZE,
    374         .transfer_buffer_policy = DMA_POLICY_STRICT,
    375 };
    376 
    377 /** Initialize USB default control pipe.
    378  *
    379  * This one is special because it must not be registered, it is registered
    380  * automatically.
     271/** Initialize USB endpoint pipe as the default zero control pipe.
    381272 *
    382273 * @param pipe Endpoint pipe to be initialized.
    383  * @param bus_session Endpoint pipe to be initialized.
    384274 * @return Error code.
    385275 */
     
    387277    usb_dev_session_t *bus_session)
    388278{
    389         const errno_t ret = usb_pipe_initialize(pipe, bus_session);
    390         if (ret)
    391                 return ret;
    392 
    393         pipe->desc = default_control_pipe;
     279        assert(pipe);
     280
     281        const errno_t rc = usb_pipe_initialize(pipe, 0, USB_TRANSFER_CONTROL,
     282            CTRL_PIPE_MIN_PACKET_SIZE, USB_DIRECTION_BOTH, 1, bus_session);
     283
    394284        pipe->auto_reset_halt = true;
    395285
    396         return EOK;
     286        return rc;
    397287}
    398288
     
    400290 *
    401291 * @param pipe Pipe to be registered.
    402  * @param ep_desc Matched endpoint descriptor
    403  * @param comp_desc Matched superspeed companion descriptro, if any
    404  * @return Error code.
    405  */
    406 errno_t usb_pipe_register(usb_pipe_t *pipe,
    407     const usb_standard_endpoint_descriptor_t *ep_desc,
    408     const usb_superspeed_endpoint_companion_descriptor_t *comp_desc)
     292 * @param interval Polling interval.
     293 * @return Error code.
     294 */
     295errno_t usb_pipe_register(usb_pipe_t *pipe, unsigned interval)
    409296{
    410297        assert(pipe);
    411298        assert(pipe->bus_session);
    412         assert(ep_desc);
    413 
    414299        async_exch_t *exch = async_exchange_begin(pipe->bus_session);
    415300        if (!exch)
    416301                return ENOMEM;
    417 
    418         usb_endpoint_descriptors_t descriptors = { 0 };
    419 
    420 #define COPY(field) descriptors.endpoint.field = ep_desc->field
    421         COPY(endpoint_address);
    422         COPY(attributes);
    423         COPY(max_packet_size);
    424         COPY(poll_interval);
    425 #undef COPY
    426 
    427 #define COPY(field) descriptors.companion.field = comp_desc->field
    428         if (comp_desc) {
    429                 COPY(max_burst);
    430                 COPY(attributes);
    431                 COPY(bytes_per_interval);
    432         }
    433 #undef COPY
    434 
    435         const errno_t ret = usbhc_register_endpoint(exch,
    436             &pipe->desc, &descriptors);
     302        const errno_t ret = usb_register_endpoint(exch, pipe->endpoint_no,
     303            pipe->transfer_type, pipe->direction, pipe->max_packet_size,
     304            pipe->packets, interval);
    437305        async_exchange_end(exch);
    438306        return ret;
     
    451319        if (!exch)
    452320                return ENOMEM;
    453 
    454         const errno_t ret = usbhc_unregister_endpoint(exch, &pipe->desc);
    455 
     321        const errno_t ret = usb_unregister_endpoint(exch, pipe->endpoint_no,
     322            pipe->direction);
    456323        async_exchange_end(exch);
    457324        return ret;
Note: See TracChangeset for help on using the changeset viewer.