Ignore:
File:
1 edited

Legend:

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

    r1d758fc rb7fd2a0  
    3636#include <usb/dev/request.h>
    3737#include <usb/usb.h>
    38 #include <usb/dma_buffer.h>
     38#include <usb_iface.h>
    3939
    4040#include <assert.h>
    41 #include <bitops.h>
    4241#include <async.h>
    43 #include <as.h>
    4442#include <errno.h>
    4543#include <mem.h>
     
    5351        assert(pipe != NULL);
    5452
    55         if (!pipe->auto_reset_halt || (pipe->desc.endpoint_no != 0)) {
     53        if (!pipe->auto_reset_halt || (pipe->endpoint_no != 0)) {
    5654                return;
    5755        }
     
    5957        /* Prevent infinite recursion. */
    6058        pipe->auto_reset_halt = false;
    61         usb_pipe_clear_halt(pipe, pipe);
     59        usb_request_clear_endpoint_halt(pipe, 0);
    6260        pipe->auto_reset_halt = true;
    63 }
    64 
    65 /* Helper structure to avoid passing loads of arguments through */
    66 typedef struct {
    67         usb_pipe_t *pipe;
    68         usb_direction_t dir;
    69         bool is_control;        // Only for checking purposes
    70 
    71         usbhc_iface_transfer_request_t req;
    72 
    73         size_t transferred_size;
    74 } transfer_t;
    75 
    76 /**
    77  * Issue a transfer in a separate exchange.
    78  */
    79 static errno_t transfer_common(transfer_t *t)
    80 {
    81         if (!t->pipe)
    82                 return EBADMEM;
    83 
    84         /* Only control writes make sense without buffer */
    85         if ((t->dir != USB_DIRECTION_OUT || !t->is_control) && t->req.size == 0)
    86                 return EINVAL;
    87 
    88         /* Nonzero size requires buffer */
    89         if (!dma_buffer_is_set(&t->req.buffer) && t->req.size != 0)
    90                 return EINVAL;
    91 
    92         /* Check expected direction */
    93         if (t->pipe->desc.direction != USB_DIRECTION_BOTH &&
    94             t->pipe->desc.direction != t->dir)
    95                 return EBADF;
    96 
    97         /* Check expected transfer type */
    98         if ((t->pipe->desc.transfer_type == USB_TRANSFER_CONTROL) != t->is_control)
    99                 return EBADF;
    100 
    101         async_exch_t *exch = async_exchange_begin(t->pipe->bus_session);
    102         if (!exch)
    103                 return ENOMEM;
    104 
    105         t->req.dir = t->dir;
    106         t->req.endpoint = t->pipe->desc.endpoint_no;
    107 
    108         const errno_t rc = usbhc_transfer(exch, &t->req, &t->transferred_size);
    109 
    110         async_exchange_end(exch);
    111 
    112         if (rc == ESTALL)
    113                 clear_self_endpoint_halt(t->pipe);
    114 
    115         return rc;
    116 }
    117 
    118 /**
    119  * Setup the transfer request inside transfer according to dma buffer provided.
    120  *
    121  * TODO: The buffer could have been allocated as a more strict one. Currently,
    122  * we assume that the policy is just the requested one.
    123  */
    124 static void setup_dma_buffer(transfer_t *t, void *base, void *ptr, size_t size)
    125 {
    126         t->req.buffer.virt = base;
    127         t->req.buffer.policy = t->pipe->desc.transfer_buffer_policy;
    128         t->req.offset = ptr - base;
    129         t->req.size = size;
    130 }
    131 
    132 /**
    133  * Compatibility wrapper for reads/writes without preallocated buffer.
    134  */
    135 static errno_t transfer_wrap_dma(transfer_t *t, void *buf, size_t size)
    136 {
    137         if (size == 0) {
    138                 setup_dma_buffer(t, NULL, NULL, 0);
    139                 return transfer_common(t);
    140         }
    141 
    142         void *dma_buf = usb_pipe_alloc_buffer(t->pipe, size);
    143         setup_dma_buffer(t, dma_buf, dma_buf, size);
    144 
    145         if (t->dir == USB_DIRECTION_OUT)
    146                 memcpy(dma_buf, buf, size);
    147 
    148         const errno_t err = transfer_common(t);
    149 
    150         if (!err && t->dir == USB_DIRECTION_IN)
    151                 memcpy(buf, dma_buf, t->transferred_size);
    152 
    153         usb_pipe_free_buffer(t->pipe, dma_buf);
    154         return err;
    155 }
    156 
    157 static errno_t prepare_control(transfer_t *t, const void *setup, size_t setup_size)
    158 {
    159         if ((setup == NULL) || (setup_size != 8))
    160                 return EINVAL;
    161        
    162         memcpy(&t->req.setup, setup, 8);
    163         return EOK;
    16461}
    16562
     
    17370 * @param[out] data_buffer Buffer for incoming data.
    17471 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
    175  * @param[out] data_transferred_size Number of bytes that were actually
    176  *                                  transferred during the DATA stage.
     72 * @param[out] data_transfered_size Number of bytes that were actually
     73 *                                  transfered during the DATA stage.
    17774 * @return Error code.
    17875 */
    17976errno_t usb_pipe_control_read(usb_pipe_t *pipe,
    18077    const void *setup_buffer, size_t setup_buffer_size,
    181     void *buffer, size_t buffer_size, size_t *transferred_size)
    182 {
    183         errno_t err;
    184         transfer_t transfer = {
    185                 .pipe = pipe,
    186                 .dir = USB_DIRECTION_IN,
    187                 .is_control = true,
    188         };
    189 
    190         if ((err = prepare_control(&transfer, setup_buffer, setup_buffer_size)))
    191                 return err;
    192 
    193         if ((err = transfer_wrap_dma(&transfer, buffer, buffer_size)))
    194                 return err;
    195 
    196         if (transferred_size)
    197                 *transferred_size = transfer.transferred_size;
    198 
    199         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;
    200113}
    201114
     
    216129{
    217130        assert(pipe);
    218         errno_t err;
    219         transfer_t transfer = {
    220                 .pipe = pipe,
    221                 .dir = USB_DIRECTION_OUT,
    222                 .is_control = true,
    223         };
    224 
    225         if ((err = prepare_control(&transfer, setup_buffer, setup_buffer_size)))
    226                 return err;
    227 
    228         return transfer_wrap_dma(&transfer, (void *) buffer, buffer_size);
    229 }
    230 
    231 /**
    232  * Allocate a buffer for data transmission, that satisfies the constraints
    233  * imposed by the host controller.
    234  *
    235  * @param[in] pipe Pipe for which the buffer is allocated
    236  * @param[in] size Size of the required buffer
    237  */
    238 void *usb_pipe_alloc_buffer(usb_pipe_t *pipe, size_t size)
    239 {
    240         dma_buffer_t buf;
    241         if (dma_buffer_alloc_policy(&buf, size, pipe->desc.transfer_buffer_policy))
    242                 return NULL;
    243 
    244         return buf.virt;
    245 }
    246 
    247 void usb_pipe_free_buffer(usb_pipe_t *pipe, void *buffer)
    248 {
    249         dma_buffer_t buf;
    250         buf.virt = buffer;
    251         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;
    252162}
    253163
     
    257167 * @param[out] buffer Buffer where to store the data.
    258168 * @param[in] size Size of the buffer (in bytes).
    259  * @param[out] size_transferred Number of bytes that were actually transferred.
     169 * @param[out] size_transfered Number of bytes that were actually transfered.
    260170 * @return Error code.
    261171 */
    262172errno_t usb_pipe_read(usb_pipe_t *pipe,
    263     void *buffer, size_t size, size_t *size_transferred)
    264 {
    265         assert(pipe);
    266         errno_t err;
    267         transfer_t transfer = {
    268                 .pipe = pipe,
    269                 .dir = USB_DIRECTION_IN,
    270         };
    271 
    272         if ((err = transfer_wrap_dma(&transfer, buffer, size)))
    273                 return err;
    274 
    275         if (size_transferred)
    276                 *size_transferred = transfer.transferred_size;
    277 
    278         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;
    279209}
    280210
     
    289219{
    290220        assert(pipe);
    291         transfer_t transfer = {
    292                 .pipe = pipe,
    293                 .dir = USB_DIRECTION_OUT,
    294         };
    295 
    296         return transfer_wrap_dma(&transfer, (void *) buffer, size);
    297 }
    298 
    299 /**
    300  * Request a read (in) transfer on an endpoint pipe, declaring that buffer
    301  * is pointing to a memory area previously allocated by usb_pipe_alloc_buffer.
    302  *
    303  * @param[in] pipe Pipe used for the transfer.
    304  * @param[in] buffer Buffer, previously allocated with usb_pipe_alloc_buffer.
    305  * @param[in] size Size of the buffer (in bytes).
    306  * @param[out] size_transferred Number of bytes that were actually transferred.
    307  * @return Error code.
    308  */
    309 errno_t usb_pipe_read_dma(usb_pipe_t *pipe, void *base, void *ptr, size_t size,
    310     size_t *size_transferred)
    311 {
    312         assert(pipe);
    313         errno_t err;
    314         transfer_t transfer = {
    315                 .pipe = pipe,
    316                 .dir = USB_DIRECTION_IN,
    317         };
    318 
    319         setup_dma_buffer(&transfer, base, ptr, size);
    320 
    321         if ((err = transfer_common(&transfer)))
    322                 return err;
    323 
    324         if (size_transferred)
    325                 *size_transferred = transfer.transferred_size;
    326 
    327         return EOK;
    328 }
    329 
    330 /**
    331  * Request a write (out) transfer on an endpoint pipe, declaring that buffer
    332  * is pointing to a memory area previously allocated by usb_pipe_alloc_buffer.
    333  *
    334  * @param[in] pipe Pipe used for the transfer.
    335  * @param[in] buffer Buffer, previously allocated with usb_pipe_alloc_buffer.
    336  * @param[in] size Size of the buffer (in bytes).
    337  * @return Error code.
    338  */
    339 errno_t usb_pipe_write_dma(usb_pipe_t *pipe, void *base, void* ptr,  size_t size)
    340 {
    341         assert(pipe);
    342         transfer_t transfer = {
    343                 .pipe = pipe,
    344                 .dir = USB_DIRECTION_OUT,
    345         };
    346 
    347         setup_dma_buffer(&transfer, base, ptr, size);
    348 
    349         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;
    350243}
    351244
     
    353246 *
    354247 * @param pipe Endpoint pipe to be initialized.
    355  * @param bus_session Endpoint pipe to be initialized.
    356  * @return Error code.
    357  */
    358 errno_t usb_pipe_initialize(usb_pipe_t *pipe, usb_dev_session_t *bus_session)
    359 {
    360         assert(pipe);
    361 
     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;
    362265        pipe->auto_reset_halt = false;
    363266        pipe->bus_session = bus_session;
     
    366269}
    367270
    368 static const usb_pipe_desc_t default_control_pipe = {
    369         .endpoint_no = 0,
    370         .transfer_type = USB_TRANSFER_CONTROL,
    371         .direction = USB_DIRECTION_BOTH,
    372         .max_transfer_size = CTRL_PIPE_MIN_PACKET_SIZE,
    373         .transfer_buffer_policy = DMA_POLICY_STRICT,
    374 };
    375 
    376 /** Initialize USB default control pipe.
    377  *
    378  * This one is special because it must not be registered, it is registered automatically.
     271/** Initialize USB endpoint pipe as the default zero control pipe.
    379272 *
    380273 * @param pipe Endpoint pipe to be initialized.
    381  * @param bus_session Endpoint pipe to be initialized.
    382  * @return Error code.
    383  */
    384 errno_t usb_pipe_initialize_default_control(usb_pipe_t *pipe, usb_dev_session_t *bus_session)
    385 {
    386         const errno_t ret = usb_pipe_initialize(pipe, bus_session);
    387         if (ret)
    388                 return ret;
    389 
    390         pipe->desc = default_control_pipe;
     274 * @return Error code.
     275 */
     276errno_t usb_pipe_initialize_default_control(usb_pipe_t *pipe,
     277    usb_dev_session_t *bus_session)
     278{
     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
    391284        pipe->auto_reset_halt = true;
    392285
    393         return EOK;
     286        return rc;
    394287}
    395288
     
    397290 *
    398291 * @param pipe Pipe to be registered.
    399  * @param ep_desc Matched endpoint descriptor
    400  * @param comp_desc Matched superspeed companion descriptro, if any
    401  * @return Error code.
    402  */
    403 errno_t usb_pipe_register(usb_pipe_t *pipe, const usb_standard_endpoint_descriptor_t *ep_desc, 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)
    404296{
    405297        assert(pipe);
    406298        assert(pipe->bus_session);
    407         assert(ep_desc);
    408 
    409299        async_exch_t *exch = async_exchange_begin(pipe->bus_session);
    410300        if (!exch)
    411301                return ENOMEM;
    412 
    413         usb_endpoint_descriptors_t descriptors;
    414 
    415 #define COPY(field) descriptors.endpoint.field = ep_desc->field
    416         COPY(endpoint_address);
    417         COPY(attributes);
    418         COPY(max_packet_size);
    419         COPY(poll_interval);
    420 #undef COPY
    421 
    422 #define COPY(field) descriptors.companion.field = comp_desc->field
    423         if (comp_desc) {
    424                 COPY(max_burst);
    425                 COPY(attributes);
    426                 COPY(bytes_per_interval);
    427         }
    428 #undef COPY
    429 
    430         const errno_t ret = usbhc_register_endpoint(exch, &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);
    431305        async_exchange_end(exch);
    432306        return ret;
     
    445319        if (!exch)
    446320                return ENOMEM;
    447 
    448         const errno_t ret = usbhc_unregister_endpoint(exch, &pipe->desc);
    449 
     321        const errno_t ret = usb_unregister_endpoint(exch, pipe->endpoint_no,
     322            pipe->direction);
    450323        async_exchange_end(exch);
    451324        return ret;
Note: See TracChangeset for help on using the changeset viewer.