Changeset 9b2f69e in mainline for uspace/drv/bus/usb/xhci/endpoint.c


Ignore:
Timestamp:
2017-10-15T20:08:16Z (7 years ago)
Author:
Petr Manek <petr.manek@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
b7db009
Parents:
816f5f4
Message:

Setting up endpoint contexts (almost) properly. Boilerplate for interrupt transfers. Simplified TRB ring initialization.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/xhci/endpoint.c

    r816f5f4 r9b2f69e  
    3535
    3636#include <usb/host/endpoint.h>
     37#include <usb/descriptor.h>
    3738
    3839#include <errno.h>
     
    5354        xhci_ep->device = NULL;
    5455
    55         usb_log_debug("Endpoint %d:%d initialized.", ep->target.address, ep->target.endpoint);
    56 
    5756        return EOK;
    5857}
     
    6362
    6463        /* FIXME: Tear down TR's? */
    65 
    66         endpoint_t *ep = &xhci_ep->base;
    67 
    68         usb_log_debug("Endpoint %d:%d destroyed.", ep->target.address, ep->target.endpoint);
    6964}
    7065
     
    7671        dev->slot_id = 0;
    7772
    78         usb_log_debug("Device %d initialized.", dev->address);
    7973        return EOK;
    8074}
     
    8377{
    8478        // TODO: Check that all endpoints are dead.
    85         usb_log_debug("Device %d destroyed.", dev->address);
     79        assert(dev);
     80}
     81
     82static inline uint8_t xhci_endpoint_ctx_offset(xhci_endpoint_t *ep)
     83{
     84        /* 0 is slot ctx, 1 is EP0, then it's EP1 out, in, EP2 out, in, etc. */
     85
     86        uint8_t off = 2 + 2 * (ep->base.target.endpoint - 1);
     87        if (ep->base.direction == USB_DIRECTION_IN)
     88                ++off;
     89
     90        return off;
     91}
     92
     93static int xhci_endpoint_type(xhci_endpoint_t *ep)
     94{
     95        const bool in = ep->base.direction == USB_DIRECTION_IN;
     96
     97        switch (ep->base.transfer_type) {
     98        case USB_TRANSFER_CONTROL:
     99                return EP_TYPE_CONTROL;
     100
     101        case USB_TRANSFER_ISOCHRONOUS:
     102                return in ? EP_TYPE_ISOCH_IN
     103                          : EP_TYPE_ISOCH_OUT;
     104
     105        case USB_TRANSFER_BULK:
     106                return in ? EP_TYPE_BULK_IN
     107                          : EP_TYPE_BULK_OUT;
     108
     109        case USB_TRANSFER_INTERRUPT:
     110                return in ? EP_TYPE_INTERRUPT_IN
     111                          : EP_TYPE_INTERRUPT_OUT;
     112        }
     113
     114        return EP_TYPE_INVALID;
     115}
     116
     117static void setup_control_ep_ctx(xhci_endpoint_t *ep, xhci_ep_ctx_t *ctx,
     118        xhci_trb_ring_t *ring)
     119{
     120        // EP0 is configured elsewhere.
     121        assert(ep->base.target.endpoint > 0);
     122
     123        XHCI_EP_TYPE_SET(*ctx, xhci_endpoint_type(ep));
     124        XHCI_EP_MAX_PACKET_SIZE_SET(*ctx, ep->base.max_packet_size);
     125        XHCI_EP_ERROR_COUNT_SET(*ctx, 3);
     126        XHCI_EP_TR_DPTR_SET(*ctx, ring->dequeue);
     127        XHCI_EP_DCS_SET(*ctx, 1);
     128}
     129
     130static void setup_bulk_ep_ctx(xhci_endpoint_t *ep, xhci_ep_ctx_t *ctx,
     131        xhci_trb_ring_t *ring, usb_superspeed_endpoint_companion_descriptor_t *ss_desc)
     132{
     133
     134        XHCI_EP_TYPE_SET(*ctx, xhci_endpoint_type(ep));
     135        XHCI_EP_MAX_PACKET_SIZE_SET(*ctx, ep->base.max_packet_size);
     136        XHCI_EP_MAX_BURST_SIZE_SET(*ctx, ep->device->usb3 ? ss_desc->max_burst : 0);
     137        XHCI_EP_ERROR_COUNT_SET(*ctx, 3);
     138
     139        // FIXME: Get maxStreams and other things from ss_desc
     140        const uint8_t maxStreams = 0;
     141        if (maxStreams > 0) {
     142                // TODO: allocate and clear primary stream array
     143                // TODO: XHCI_EP_MAX_P_STREAMS_SET(ctx, psa_size);
     144                // TODO: XHCI_EP_TR_DPTR_SET(ctx, psa_start_phys_addr);
     145                // TODO: set HID
     146                // TODO: set LSA
     147        } else {
     148                XHCI_EP_MAX_P_STREAMS_SET(*ctx, 0);
     149                /* FIXME physical pointer? */
     150                XHCI_EP_TR_DPTR_SET(*ctx, ring->dequeue);
     151                XHCI_EP_DCS_SET(*ctx, 1);
     152        }
     153}
     154
     155static void setup_isoch_ep_ctx(xhci_endpoint_t *ep, xhci_ep_ctx_t *ctx,
     156        xhci_trb_ring_t *ring, usb_superspeed_endpoint_companion_descriptor_t *ss_desc)
     157{
     158        XHCI_EP_TYPE_SET(*ctx, xhci_endpoint_type(ep));
     159        XHCI_EP_MAX_PACKET_SIZE_SET(*ctx, ep->base.max_packet_size & 0x07FF);
     160        XHCI_EP_MAX_BURST_SIZE_SET(*ctx, ss_desc->max_burst);
     161        // FIXME: get Mult field from SS companion descriptor somehow
     162        XHCI_EP_MULT_SET(*ctx, 0);
     163        XHCI_EP_ERROR_COUNT_SET(*ctx, 0);
     164        /* FIXME physical pointer? */
     165        XHCI_EP_TR_DPTR_SET(*ctx, ring->dequeue);
     166        XHCI_EP_DCS_SET(*ctx, 1);
     167        // TODO: max ESIT payload
     168}
     169
     170static void setup_interrupt_ep_ctx(xhci_endpoint_t *ep, xhci_ep_ctx_t *ctx,
     171        xhci_trb_ring_t *ring, usb_superspeed_endpoint_companion_descriptor_t *ss_desc)
     172{
     173        XHCI_EP_TYPE_SET(*ctx, xhci_endpoint_type(ep));
     174        XHCI_EP_MAX_PACKET_SIZE_SET(*ctx, ep->base.max_packet_size & 0x07FF);
     175        XHCI_EP_MAX_BURST_SIZE_SET(*ctx, ss_desc->max_burst);
     176        XHCI_EP_MULT_SET(*ctx, 0);
     177        XHCI_EP_ERROR_COUNT_SET(*ctx, 3);
     178        /* FIXME physical pointer? */
     179        XHCI_EP_TR_DPTR_SET(*ctx, ring->dequeue);
     180        XHCI_EP_DCS_SET(*ctx, 1);
     181        // TODO: max ESIT payload
    86182}
    87183
     
    92188        assert(!ep->device);
    93189
     190        int err;
     191        xhci_input_ctx_t *ictx = NULL;
     192        xhci_trb_ring_t *ep_ring = NULL;
     193        if (ep->base.target.endpoint > 0) {
     194                // FIXME: Retrieve this from somewhere, if applicable.
     195                usb_superspeed_endpoint_companion_descriptor_t ss_desc;
     196                memset(&ss_desc, 0, sizeof(ss_desc));
     197
     198                // Prepare input context.
     199                ictx = malloc(sizeof(xhci_input_ctx_t));
     200                if (!ictx) {
     201                        return ENOMEM;
     202                }
     203
     204                memset(ictx, 0, sizeof(xhci_input_ctx_t));
     205
     206                // Quoting sec. 4.6.6: A1, D0, D1 are down, A0 is up.
     207                XHCI_INPUT_CTRL_CTX_ADD_CLEAR(ictx->ctrl_ctx, 1);
     208                XHCI_INPUT_CTRL_CTX_DROP_CLEAR(ictx->ctrl_ctx, 0);
     209                XHCI_INPUT_CTRL_CTX_DROP_CLEAR(ictx->ctrl_ctx, 1);
     210                XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, 0);
     211
     212                const uint8_t ep_offset = xhci_endpoint_ctx_offset(ep);
     213                XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, ep_offset);
     214
     215                ep_ring = malloc(sizeof(xhci_trb_ring_t));
     216                if (!ep_ring) {
     217                        err = ENOMEM;
     218                        goto err_ictx;
     219                }
     220
     221                // FIXME: This ring need not be allocated all the time.
     222                err = xhci_trb_ring_init(ep_ring);
     223                if (err)
     224                        goto err_ring;
     225
     226                switch (ep->base.transfer_type) {
     227                case USB_TRANSFER_CONTROL:
     228                        setup_control_ep_ctx(ep, &ictx->endpoint_ctx[ep_offset], ep_ring);
     229                        break;
     230
     231                case USB_TRANSFER_BULK:
     232                        setup_bulk_ep_ctx(ep, &ictx->endpoint_ctx[ep_offset], ep_ring, &ss_desc);
     233                        break;
     234
     235                case USB_TRANSFER_ISOCHRONOUS:
     236                        setup_isoch_ep_ctx(ep, &ictx->endpoint_ctx[ep_offset], ep_ring, &ss_desc);
     237                        break;
     238
     239                case USB_TRANSFER_INTERRUPT:
     240                        setup_interrupt_ep_ctx(ep, &ictx->endpoint_ctx[ep_offset], ep_ring, &ss_desc);
     241                        break;
     242
     243                }
     244
     245                dev->hc->dcbaa_virt[dev->slot_id].trs[ep->base.target.endpoint] = ep_ring;
     246
     247                // Issue configure endpoint command (sec 4.3.5).
     248                xhci_cmd_t cmd;
     249                xhci_cmd_init(&cmd);
     250
     251                cmd.slot_id = dev->slot_id;
     252                xhci_send_configure_endpoint_command(dev->hc, &cmd, ictx);
     253                if ((err = xhci_cmd_wait(&cmd, 100000)) != EOK)
     254                        goto err_cmd;
     255
     256                xhci_cmd_fini(&cmd);
     257        }
     258
    94259        ep->device = dev;
    95260        dev->endpoints[ep->base.target.endpoint] = ep;
    96261        ++dev->active_endpoint_count;
    97262        return EOK;
     263
     264err_cmd:
     265err_ring:
     266        if (ep_ring) {
     267                xhci_trb_ring_fini(ep_ring);
     268                free(ep_ring);
     269        }
     270err_ictx:
     271        free(ictx);
     272        return err;
    98273}
    99274
     
    103278        assert(dev->endpoints[ep->base.target.endpoint]);
    104279        assert(dev == ep->device);
     280
     281        // TODO: Issue configure endpoint command to drop this endpoint.
    105282
    106283        ep->device = NULL;
Note: See TracChangeset for help on using the changeset viewer.