Changeset df6ded8 in mainline for uspace/drv/bus/usb/ehci/hc.c


Ignore:
Timestamp:
2018-02-28T16:37:50Z (7 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
1b20da0
Parents:
f5e5f73 (diff), b2dca8de (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
Jakub Jermar <jakub@…> (2018-02-28 16:06:42)
git-committer:
Jakub Jermar <jakub@…> (2018-02-28 16:37:50)
Message:

Merge github.com:helenos-xhci-team/helenos

This commit merges support for USB 3 and generally refactors, fixes,
extends and cleans up the existing USB framework.

Notable additions and features:

  • new host controller driver has been implemented to control various xHC models (among others, NEC Renesas uPD720200)
  • isochronous data transfer mode
  • support for explicit USB device removal
  • USB tablet driver
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/ehci/hc.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    4546#include <usb/debug.h>
    4647#include <usb/usb.h>
    47 #include <usb/host/utils/malloc32.h>
     48#include <usb/host/utility.h>
    4849
    4950#include "ehci_batch.h"
     
    8990};
    9091
    91 static void hc_start(hc_t *instance);
    9292static errno_t hc_init_memory(hc_t *instance);
    9393
     
    100100 * @return Error code.
    101101 */
    102 errno_t ehci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)
     102errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
    103103{
    104104        assert(code);
    105105        assert(hw_res);
     106        hc_t *instance = hcd_to_hc(hcd);
    106107
    107108        if (hw_res->irqs.count != 1 || hw_res->mem_ranges.count != 1)
     
    130131
    131132        memcpy(code->cmds, ehci_irq_commands, sizeof(ehci_irq_commands));
    132         ehci_caps_regs_t *caps = NULL;
    133 
    134         errno_t ret = pio_enable_range(&regs, (void**)&caps);
    135         if (ret != EOK) {
    136                 free(code->ranges);
    137                 free(code->cmds);
    138                 return ret;
    139         }
    140133
    141134        ehci_regs_t *registers =
    142             (ehci_regs_t *)(RNGABSPTR(regs) + EHCI_RD8(caps->caplength));
     135                (ehci_regs_t *)(RNGABSPTR(regs) + EHCI_RD8(instance->caps->caplength));
    143136        code->cmds[0].addr = (void *) &registers->usbsts;
    144137        code->cmds[3].addr = (void *) &registers->usbsts;
    145138        EHCI_WR(code->cmds[1].value, EHCI_USED_INTERRUPTS);
    146139
    147         usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n",
     140        usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.",
    148141            RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
    149142
     
    159152 * @return Error code
    160153 */
    161 errno_t hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
    162 {
    163         assert(instance);
     154errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
     155{
     156        hc_t *instance = hcd_to_hc(hcd);
    164157        assert(hw_res);
    165158        if (hw_res->mem_ranges.count != 1 ||
     
    172165        if (ret != EOK) {
    173166                usb_log_error("HC(%p): Failed to gain access to device "
    174                     "registers: %s.\n", instance, str_error(ret));
     167                    "registers: %s.", instance, str_error(ret));
    175168                return ret;
    176169        }
     170
    177171        usb_log_info("HC(%p): Device registers at %"PRIx64" (%zuB) accessible.",
    178172            instance, hw_res->mem_ranges.ranges[0].address.absolute,
     
    184178            + EHCI_RD8(instance->caps->caplength));
    185179
    186         list_initialize(&instance->pending_batches);
     180        list_initialize(&instance->pending_endpoints);
    187181        fibril_mutex_initialize(&instance->guard);
    188182        fibril_condvar_initialize(&instance->async_doorbell);
     
    197191        usb_log_info("HC(%p): Initializing RH(%p).", instance, &instance->rh);
    198192        ehci_rh_init(
    199             &instance->rh, instance->caps, instance->registers, "ehci rh");
    200         usb_log_debug("HC(%p): Starting HW.", instance);
    201         hc_start(instance);
    202 
     193            &instance->rh, instance->caps, instance->registers, &instance->guard,
     194            "ehci rh");
     195
     196        ehci_bus_init(&instance->bus, instance);
     197        hc_device_setup(hcd, (bus_t *) &instance->bus);
    203198        return EOK;
    204199}
     
    208203 * @param[in] instance Host controller structure to use.
    209204 */
    210 void hc_fini(hc_t *instance)
    211 {
    212         assert(instance);
    213         //TODO: stop the hw
    214 #if 0
    215         endpoint_list_fini(&instance->async_list);
    216         endpoint_list_fini(&instance->int_list);
    217         return_page(instance->periodic_list_base);
    218 #endif
     205int hc_gone(hc_device_t *hcd)
     206{
     207        hc_t *hc = hcd_to_hc(hcd);
     208        endpoint_list_fini(&hc->async_list);
     209        endpoint_list_fini(&hc->int_list);
     210        dma_buffer_free(&hc->dma_buffer);
     211        return EOK;
    219212};
    220213
     
    224217        assert(ep);
    225218        ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep);
    226         usb_log_debug("HC(%p) enqueue EP(%d:%d:%s:%s)\n", instance,
    227             ep->address, ep->endpoint,
     219        usb_log_debug("HC(%p) enqueue EP(%d:%d:%s:%s)", instance,
     220            ep->device->address, ep->endpoint,
    228221            usb_str_transfer_type_short(ep->transfer_type),
    229222            usb_str_direction(ep->direction));
     
    248241        assert(ep);
    249242        ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep);
    250         usb_log_debug("HC(%p) dequeue EP(%d:%d:%s:%s)\n", instance,
    251             ep->address, ep->endpoint,
     243        usb_log_debug("HC(%p) dequeue EP(%d:%d:%s:%s)", instance,
     244            ep->device->address, ep->endpoint,
    252245            usb_str_transfer_type_short(ep->transfer_type),
    253246            usb_str_direction(ep->direction));
     
    273266}
    274267
    275 errno_t ehci_hc_status(hcd_t *hcd, uint32_t *status)
    276 {
    277         assert(hcd);
    278         hc_t *instance = hcd_get_driver_data(hcd);
    279         assert(instance);
     268errno_t ehci_hc_status(bus_t *bus_base, uint32_t *status)
     269{
     270        assert(bus_base);
    280271        assert(status);
     272
     273        ehci_bus_t *bus = (ehci_bus_t *) bus_base;
     274        hc_t *hc = bus->hc;
     275        assert(hc);
     276
    281277        *status = 0;
    282         if (instance->registers) {
    283                 *status = EHCI_RD(instance->registers->usbsts);
    284                 EHCI_WR(instance->registers->usbsts, *status);
    285         }
    286         usb_log_debug2("HC(%p): Read status: %x", instance, *status);
     278        if (hc->registers) {
     279                *status = EHCI_RD(hc->registers->usbsts);
     280                EHCI_WR(hc->registers->usbsts, *status);
     281        }
     282        usb_log_debug2("HC(%p): Read status: %x", hc, *status);
    287283        return EOK;
    288284}
     
    294290 * @return Error code.
    295291 */
    296 errno_t ehci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    297 {
    298         assert(hcd);
    299         hc_t *instance = hcd_get_driver_data(hcd);
    300         assert(instance);
     292errno_t ehci_hc_schedule(usb_transfer_batch_t *batch)
     293{
     294        assert(batch);
     295
     296        ehci_bus_t *bus = (ehci_bus_t *) endpoint_get_bus(batch->ep);
     297        hc_t *hc = bus->hc;
     298        assert(hc);
    301299
    302300        /* Check for root hub communication */
    303         if (batch->ep->address == ehci_rh_get_address(&instance->rh)) {
     301        if (batch->target.address == ehci_rh_get_address(&hc->rh)) {
    304302                usb_log_debug("HC(%p): Scheduling BATCH(%p) for RH(%p)",
    305                     instance, batch, &instance->rh);
    306                 return ehci_rh_schedule(&instance->rh, batch);
    307         }
     303                    hc, batch, &hc->rh);
     304                return ehci_rh_schedule(&hc->rh, batch);
     305        }
     306
     307        endpoint_t * const ep = batch->ep;
     308        ehci_endpoint_t * const ehci_ep = ehci_endpoint_get(ep);
    308309        ehci_transfer_batch_t *ehci_batch = ehci_transfer_batch_get(batch);
    309         if (!ehci_batch)
    310                 return ENOMEM;
    311 
    312         fibril_mutex_lock(&instance->guard);
    313         usb_log_debug2("HC(%p): Appending BATCH(%p)", instance, batch);
    314         list_append(&ehci_batch->link, &instance->pending_batches);
    315         usb_log_debug("HC(%p): Committing BATCH(%p)", instance, batch);
     310
     311        int err;
     312
     313        if ((err = ehci_transfer_batch_prepare(ehci_batch)))
     314                return err;
     315
     316        fibril_mutex_lock(&hc->guard);
     317
     318        if ((err = endpoint_activate_locked(ep, batch))) {
     319                fibril_mutex_unlock(&hc->guard);
     320                return err;
     321        }
     322
     323        usb_log_debug("HC(%p): Committing BATCH(%p)", hc, batch);
    316324        ehci_transfer_batch_commit(ehci_batch);
    317325
    318         fibril_mutex_unlock(&instance->guard);
     326        /* Enqueue endpoint to the checked list */
     327        usb_log_debug2("HC(%p): Appending BATCH(%p)", hc, batch);
     328        list_append(&ehci_ep->pending_link, &hc->pending_endpoints);
     329
     330        fibril_mutex_unlock(&hc->guard);
    319331        return EOK;
    320332}
     
    325337 * @param[in] status Value of the status register at the time of interrupt.
    326338 */
    327 void ehci_hc_interrupt(hcd_t *hcd, uint32_t status)
    328 {
    329         assert(hcd);
    330         hc_t *instance = hcd_get_driver_data(hcd);
    331         status = EHCI_RD(status);
    332         assert(instance);
    333 
    334         usb_log_debug2("HC(%p): Interrupt: %"PRIx32, instance, status);
     339void ehci_hc_interrupt(bus_t *bus_base, uint32_t status)
     340{
     341        assert(bus_base);
     342
     343        ehci_bus_t *bus = (ehci_bus_t *) bus_base;
     344        hc_t *hc = bus->hc;
     345        assert(hc);
     346
     347        usb_log_debug2("HC(%p): Interrupt: %"PRIx32, hc, status);
    335348        if (status & USB_STS_PORT_CHANGE_FLAG) {
    336                 ehci_rh_interrupt(&instance->rh);
     349                ehci_rh_interrupt(&hc->rh);
    337350        }
    338351
    339352        if (status & USB_STS_IRQ_ASYNC_ADVANCE_FLAG) {
    340                 fibril_mutex_lock(&instance->guard);
    341                 usb_log_debug2("HC(%p): Signaling doorbell", instance);
    342                 fibril_condvar_broadcast(&instance->async_doorbell);
    343                 fibril_mutex_unlock(&instance->guard);
     353                fibril_mutex_lock(&hc->guard);
     354                usb_log_debug2("HC(%p): Signaling doorbell", hc);
     355                fibril_condvar_broadcast(&hc->async_doorbell);
     356                fibril_mutex_unlock(&hc->guard);
    344357        }
    345358
    346359        if (status & (USB_STS_IRQ_FLAG | USB_STS_ERR_IRQ_FLAG)) {
    347                 fibril_mutex_lock(&instance->guard);
    348 
    349                 usb_log_debug2("HC(%p): Scanning %lu pending batches", instance,
    350                         list_count(&instance->pending_batches));
    351                 list_foreach_safe(instance->pending_batches, current, next) {
    352                         ehci_transfer_batch_t *batch =
    353                             ehci_transfer_batch_from_link(current);
    354 
    355                         if (ehci_transfer_batch_is_complete(batch)) {
     360                fibril_mutex_lock(&hc->guard);
     361
     362                usb_log_debug2("HC(%p): Scanning %lu pending endpoints", hc,
     363                        list_count(&hc->pending_endpoints));
     364                list_foreach_safe(hc->pending_endpoints, current, next) {
     365                        ehci_endpoint_t *ep
     366                                = list_get_instance(current, ehci_endpoint_t, pending_link);
     367
     368                        ehci_transfer_batch_t *batch
     369                                = ehci_transfer_batch_get(ep->base.active_batch);
     370                        assert(batch);
     371
     372                        if (ehci_transfer_batch_check_completed(batch)) {
     373                                endpoint_deactivate_locked(&ep->base);
    356374                                list_remove(current);
    357                                 ehci_transfer_batch_finish_dispose(batch);
     375                                hc_reset_toggles(&batch->base, &ehci_ep_toggle_reset);
     376                                usb_transfer_batch_finish(&batch->base);
    358377                        }
    359378                }
    360                 fibril_mutex_unlock(&instance->guard);
     379                fibril_mutex_unlock(&hc->guard);
     380
     381
    361382        }
    362383
    363384        if (status & USB_STS_HOST_ERROR_FLAG) {
    364                 usb_log_fatal("HCD(%p): HOST SYSTEM ERROR!", instance);
     385                usb_log_fatal("HCD(%p): HOST SYSTEM ERROR!", hc);
    365386                //TODO do something here
    366387        }
     
    371392 * @param[in] instance EHCI hc driver structure.
    372393 */
    373 void hc_start(hc_t *instance)
    374 {
    375         assert(instance);
     394int hc_start(hc_device_t *hcd)
     395{
     396        hc_t *instance = hcd_to_hc(hcd);
     397        usb_log_debug("HC(%p): Starting HW.", instance);
     398
    376399        /* Turn off the HC if it's running, Reseting a running device is
    377400         * undefined */
     
    404427
    405428        /* Enable periodic list */
    406         assert(instance->periodic_list_base);
     429        assert(instance->periodic_list);
    407430        uintptr_t phys_base =
    408             addr_to_phys((void*)instance->periodic_list_base);
     431            addr_to_phys((void*)instance->periodic_list);
    409432        assert((phys_base & USB_PERIODIC_LIST_BASE_MASK) == phys_base);
    410433        EHCI_WR(instance->registers->periodiclistbase, phys_base);
     
    425448        usb_log_debug("HC(%p): HW started.", instance);
    426449
    427         usb_log_debug2("HC(%p): Registers: \n"
    428             "\tUSBCMD(%p): %x(0x00080000 = at least 1ms between interrupts)\n"
    429             "\tUSBSTS(%p): %x(0x00001000 = HC halted)\n"
    430             "\tUSBINT(%p): %x(0x0 = no interrupts).\n"
    431             "\tCONFIG(%p): %x(0x0 = ports controlled by companion hc).\n",
     450        usb_log_debug2("HC(%p): Registers: "
     451            "\tUSBCMD(%p): %x(0x00080000 = at least 1ms between interrupts)"
     452            "\tUSBSTS(%p): %x(0x00001000 = HC halted)"
     453            "\tUSBINT(%p): %x(0x0 = no interrupts)."
     454            "\tCONFIG(%p): %x(0x0 = ports controlled by companion hc).",
    432455            instance,
    433456            &instance->registers->usbcmd, EHCI_RD(instance->registers->usbcmd),
     
    438461        EHCI_WR(instance->registers->usbsts, EHCI_RD(instance->registers->usbsts));
    439462        EHCI_WR(instance->registers->usbintr, EHCI_USED_INTERRUPTS);
     463
     464        return EOK;
     465}
     466
     467/**
     468 * Setup roothub as a virtual hub.
     469 */
     470int hc_setup_roothub(hc_device_t *hcd)
     471{
     472        return hc_setup_virtual_root_hub(hcd, USB_SPEED_HIGH);
    440473}
    441474
     
    473506
    474507        /* Take 1024 periodic list heads, we ignore low mem options */
    475         instance->periodic_list_base = get_page();
    476         if (!instance->periodic_list_base) {
     508        if (dma_buffer_alloc(&instance->dma_buffer, PAGE_SIZE)) {
    477509                usb_log_error("HC(%p): Failed to get ISO schedule page.",
    478510                    instance);
     
    481513                return ENOMEM;
    482514        }
     515        instance->periodic_list = instance->dma_buffer.virt;
    483516
    484517        usb_log_debug2("HC(%p): Initializing Periodic list.", instance);
    485         for (unsigned i = 0;
    486             i < PAGE_SIZE/sizeof(instance->periodic_list_base[0]); ++i)
     518        for (unsigned i = 0; i < PAGE_SIZE/sizeof(link_pointer_t); ++i)
    487519        {
    488520                /* Disable everything for now */
    489                 instance->periodic_list_base[i] =
     521                instance->periodic_list[i] =
    490522                    LINK_POINTER_QH(addr_to_phys(instance->int_list.list_head));
    491523        }
Note: See TracChangeset for help on using the changeset viewer.