Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 9b2f69e in mainline


Ignore:
Timestamp:
2017-10-15T20:08:16Z (3 years ago)
Author:
Petr Manek <petr.manek@…>
Branches:
master
Children:
b7db009
Parents:
816f5f4
Message:

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

Location:
uspace/drv/bus/usb/xhci
Files:
9 edited

Legend:

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

    r816f5f4 r9b2f69e  
    187187        ret_dev->device = dev;
    188188
     189        usb_log_debug("Device(%d) registered to XHCI bus.", dev->address);
     190
    189191        hash_table_insert(&bus->devices, &ret_dev->link);
    190192        *hashed_dev = ret_dev;
     
    200202static int hashed_device_remove(xhci_bus_t *bus, hashed_device_t *hashed_dev)
    201203{
     204        usb_log_debug("Device(%d) released from XHCI bus.", hashed_dev->device->address);
     205
    202206        hash_table_remove(&bus->devices, &hashed_dev->device->address);
    203207        xhci_device_fini(hashed_dev->device);
     
    225229        }
    226230
     231        usb_log_debug("Endpoint(%d:%d) registered to XHCI bus.", ep->target.address, ep->target.endpoint);
     232
    227233        return xhci_device_add_endpoint(hashed_dev->device, xhci_endpoint_get(ep));
    228234}
     
    232238        xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
    233239        assert(bus);
     240
     241        usb_log_debug("Endpoint(%d:%d) released from XHCI bus.", ep->target.address, ep->target.endpoint);
    234242
    235243        hashed_device_t *hashed_dev;
  • 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;
  • uspace/drv/bus/usb/xhci/endpoint.h

    r816f5f4 r9b2f69e  
    4949typedef struct xhci_bus xhci_bus_t;
    5050
    51 #define XHCI_DEVICE_MAX_ENDPOINTS 32
    52 
    5351enum {
    5452        EP_TYPE_INVALID = 0,
     
    8179
    8280        /** All endpoints of the device. Inactive ones are NULL */
    83         xhci_endpoint_t *endpoints[XHCI_DEVICE_MAX_ENDPOINTS];
     81        xhci_endpoint_t *endpoints[XHCI_EP_COUNT];
    8482
    8583        /** Number of non-NULL endpoints. Reference count of sorts. */
    8684        uint8_t active_endpoint_count;
     85
     86        /** Need HC to schedule commands from bus callbacks. TODO: Move this elsewhere. */
     87        xhci_hc_t *hc;
     88
     89        /** Flag indicating whether the device is USB3 (it's USB2 otherwise). */
     90        bool usb3;
    8791} xhci_device_t;
    8892
  • uspace/drv/bus/usb/xhci/hc.c

    r816f5f4 r9b2f69e  
    201201        }
    202202
    203         if ((err = xhci_trb_ring_init(&hc->command_ring, hc)))
     203        if ((err = xhci_trb_ring_init(&hc->command_ring)))
    204204                goto err_dcbaa_virt;
    205205
    206         if ((err = xhci_event_ring_init(&hc->event_ring, hc)))
     206        if ((err = xhci_event_ring_init(&hc->event_ring)))
    207207                goto err_cmd_ring;
    208208
     
    462462        assert(batch);
    463463
    464         usb_log_debug2("EP(%d:%d) started %s transfer of size %lu.",
     464        usb_log_debug2("Endpoint(%d:%d) started %s transfer of size %lu.",
    465465                batch->ep->target.address, batch->ep->target.endpoint,
    466466                usb_str_transfer_type(batch->ep->transfer_type),
     
    482482                return xhci_schedule_bulk_transfer(hc, batch);
    483483        case USB_TRANSFER_INTERRUPT:
    484                 /* TODO: Implement me. */
    485                 usb_log_error("Interrupt transfers are not yet implemented!");
    486                 return ENOTSUP;
     484                return xhci_schedule_interrupt_transfer(hc, batch);
    487485        }
    488486
  • uspace/drv/bus/usb/xhci/rh.c

    r816f5f4 r9b2f69e  
    120120        }
    121121
    122         err = xhci_trb_ring_init(ep_ring, hc);
     122        err = xhci_trb_ring_init(ep_ring);
    123123        if (err)
    124124                goto err_ring;
     
    181181        xhci_dev->device = dev;
    182182        xhci_dev->slot_id = slot_id;
     183        xhci_dev->usb3 = speed->major == 3;
     184        xhci_dev->hc = hc;
    183185
    184186        // TODO: Save anything else?
  • uspace/drv/bus/usb/xhci/transfers.c

    r816f5f4 r9b2f69e  
    266266}
    267267
    268 int xhci_schedule_bulk_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch) {
     268int xhci_schedule_bulk_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch)
     269{
    269270        if (batch->setup_size) {
    270271                usb_log_warning("Setup packet present for a bulk transfer.");
     
    276277
    277278        xhci_transfer_t *transfer = xhci_transfer_alloc(batch);
    278         memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size);
     279        if (!transfer->direction) {
     280                // Sending stuff from host to device, we need to copy the actual data.
     281                memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size);
     282        }
    279283
    280284        xhci_trb_t trb;
     
    300304}
    301305
     306int xhci_schedule_interrupt_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch)
     307{
     308        /* FIXME: Removing the next 2 rows causes QEMU to crash lol */
     309        usb_log_warning("Interrupt transfers not yet implemented!");
     310        return ENOTSUP;
     311
     312        if (batch->setup_size) {
     313                usb_log_warning("Setup packet present for a interrupt transfer.");
     314        }
     315
     316        xhci_endpoint_t *xhci_ep = xhci_endpoint_get(batch->ep);
     317        uint8_t slot_id = xhci_ep->device->slot_id;
     318        xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[batch->ep->target.endpoint];
     319
     320        xhci_transfer_t *transfer = xhci_transfer_alloc(batch);
     321        if (!transfer->direction) {
     322                // Sending stuff from host to device, we need to copy the actual data.
     323                memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size);
     324        }
     325
     326        xhci_trb_t trb;
     327        memset(&trb, 0, sizeof(xhci_trb_t));
     328        trb.parameter = addr_to_phys(transfer->hc_buffer);
     329
     330        // data size (sent for OUT, or buffer size)
     331        TRB_CTRL_SET_XFER_LEN(trb, batch->buffer_size);
     332        // FIXME: TD size 4.11.2.4
     333        TRB_CTRL_SET_TD_SIZE(trb, 1);
     334
     335        // we want an interrupt after this td is done
     336        TRB_CTRL_SET_IOC(trb, 1);
     337
     338        TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
     339
     340        xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
     341        list_append(&transfer->link, &hc->transfers);
     342
     343        const uint8_t target = 2 * batch->ep->target.endpoint
     344                + (batch->ep->direction == USB_DIRECTION_IN ? 1 : 0);
     345        usb_log_debug("Ringing doorbell for slot_id = %d, target = %d", slot_id, target);
     346        return hc_ring_doorbell(hc, slot_id, target);
     347}
     348
    302349int xhci_handle_transfer_event(xhci_hc_t* hc, xhci_trb_t* trb)
    303350{
  • uspace/drv/bus/usb/xhci/transfers.h

    r816f5f4 r9b2f69e  
    5454int xhci_schedule_control_transfer(xhci_hc_t*, usb_transfer_batch_t*);
    5555int xhci_schedule_bulk_transfer(xhci_hc_t*, usb_transfer_batch_t*);
     56int xhci_schedule_interrupt_transfer(xhci_hc_t*, usb_transfer_batch_t*);
    5657int xhci_handle_transfer_event(xhci_hc_t*, xhci_trb_t*);
  • uspace/drv/bus/usb/xhci/trb_ring.c

    r816f5f4 r9b2f69e  
    9292 * Event when it fails, the structure needs to be finalized.
    9393 */
    94 int xhci_trb_ring_init(xhci_trb_ring_t *ring, xhci_hc_t *hc)
     94int xhci_trb_ring_init(xhci_trb_ring_t *ring)
    9595{
    9696        struct trb_segment *segment;
     
    237237 * Even when it fails, the structure needs to be finalized.
    238238 */
    239 int xhci_event_ring_init(xhci_event_ring_t *ring, xhci_hc_t *hc)
     239int xhci_event_ring_init(xhci_event_ring_t *ring)
    240240{
    241241        struct trb_segment *segment;
  • uspace/drv/bus/usb/xhci/trb_ring.h

    r816f5f4 r9b2f69e  
    7373} xhci_trb_ring_t;
    7474
    75 int xhci_trb_ring_init(xhci_trb_ring_t *, xhci_hc_t *);
     75int xhci_trb_ring_init(xhci_trb_ring_t *);
    7676int xhci_trb_ring_fini(xhci_trb_ring_t *);
    7777int xhci_trb_ring_enqueue(xhci_trb_ring_t *, xhci_trb_t *, uintptr_t *);
     
    110110} xhci_event_ring_t;
    111111
    112 int xhci_event_ring_init(xhci_event_ring_t *, xhci_hc_t *);
     112int xhci_event_ring_init(xhci_event_ring_t *);
    113113int xhci_event_ring_fini(xhci_event_ring_t *);
    114114int xhci_event_ring_dequeue(xhci_event_ring_t *, xhci_trb_t *);
Note: See TracChangeset for help on using the changeset viewer.