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


Ignore:
Timestamp:
2018-02-28T16:37:50Z (6 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/ohci/hc.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    4546
    4647#include <usb/debug.h>
     48#include <usb/host/utility.h>
    4749#include <usb/usb.h>
    4850
    49 #include "ohci_endpoint.h"
     51#include "ohci_bus.h"
    5052#include "ohci_batch.h"
    5153
     
    8991};
    9092
    91 static void hc_gain_control(hc_t *instance);
    92 static void hc_start(hc_t *instance);
    9393static errno_t hc_init_transfer_lists(hc_t *instance);
    9494static errno_t hc_init_memory(hc_t *instance);
     
    103103 * @return Error code.
    104104 */
    105 errno_t ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)
     105errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
    106106{
    107107        assert(code);
     
    138138        OHCI_WR(code->cmds[1].value, OHCI_USED_INTERRUPTS);
    139139
    140         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.",
    141141            RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
    142142
     
    152152 * @return Error code
    153153 */
    154 errno_t hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
    155 {
    156         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);
    157157        assert(hw_res);
    158158        if (hw_res->mem_ranges.count != 1 ||
     
    163163            (void **) &instance->registers);
    164164        if (ret != EOK) {
    165                 usb_log_error("Failed to gain access to registers: %s.\n",
     165                usb_log_error("Failed to gain access to registers: %s.",
    166166                    str_error(ret));
    167167                return ret;
    168168        }
    169         usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n",
     169        usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.",
    170170            hw_res->mem_ranges.ranges[0].address.absolute,
    171171            hw_res->mem_ranges.ranges[0].size);
    172172
    173         list_initialize(&instance->pending_batches);
     173        list_initialize(&instance->pending_endpoints);
    174174        fibril_mutex_initialize(&instance->guard);
    175         instance->hw_interrupts = interrupts;
    176175
    177176        ret = hc_init_memory(instance);
    178177        if (ret != EOK) {
    179                 usb_log_error("Failed to create OHCI memory structures: %s.\n",
     178                usb_log_error("Failed to create OHCI memory structures: %s.",
    180179                    str_error(ret));
    181180                // TODO: We should disable pio access here
     
    183182        }
    184183
    185         hc_gain_control(instance);
    186 
    187         ohci_rh_init(&instance->rh, instance->registers, "ohci rh");
    188         hc_start(instance);
    189 
    190184        return EOK;
    191185}
     
    195189 * @param[in] instance Host controller structure to use.
    196190 */
    197 void hc_fini(hc_t *instance)
     191int hc_gone(hc_device_t *instance)
    198192{
    199193        assert(instance);
    200194        /* TODO: implement*/
    201 };
     195        return ENOTSUP;
     196}
    202197
    203198void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)
     
    269264}
    270265
    271 errno_t ohci_hc_status(hcd_t *hcd, uint32_t *status)
    272 {
    273         assert(hcd);
     266errno_t ohci_hc_status(bus_t *bus_base, uint32_t *status)
     267{
     268        assert(bus_base);
    274269        assert(status);
    275         hc_t *instance = hcd_get_driver_data(hcd);
    276         assert(instance);
    277 
    278         if (instance->registers){
    279                 *status = OHCI_RD(instance->registers->interrupt_status);
    280                 OHCI_WR(instance->registers->interrupt_status, *status);
     270
     271        ohci_bus_t *bus = (ohci_bus_t *) bus_base;
     272        hc_t *hc = bus->hc;
     273        assert(hc);
     274
     275        if (hc->registers){
     276                *status = OHCI_RD(hc->registers->interrupt_status);
     277                OHCI_WR(hc->registers->interrupt_status, *status);
    281278        }
    282279        return EOK;
     
    289286 * @return Error code.
    290287 */
    291 errno_t ohci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    292 {
    293         assert(hcd);
    294         hc_t *instance = hcd_get_driver_data(hcd);
    295         assert(instance);
     288errno_t ohci_hc_schedule(usb_transfer_batch_t *batch)
     289{
     290        assert(batch);
     291
     292        ohci_bus_t *bus = (ohci_bus_t *) endpoint_get_bus(batch->ep);
     293        hc_t *hc = bus->hc;
     294        assert(hc);
    296295
    297296        /* Check for root hub communication */
    298         if (batch->ep->address == ohci_rh_get_address(&instance->rh)) {
    299                 usb_log_debug("OHCI root hub request.\n");
    300                 return ohci_rh_schedule(&instance->rh, batch);
    301         }
     297        if (batch->target.address == ohci_rh_get_address(&hc->rh)) {
     298                usb_log_debug("OHCI root hub request.");
     299                return ohci_rh_schedule(&hc->rh, batch);
     300        }
     301
     302        endpoint_t *ep = batch->ep;
     303        ohci_endpoint_t * const ohci_ep = ohci_endpoint_get(ep);
    302304        ohci_transfer_batch_t *ohci_batch = ohci_transfer_batch_get(batch);
    303         if (!ohci_batch)
    304                 return ENOMEM;
    305 
    306         fibril_mutex_lock(&instance->guard);
    307         list_append(&ohci_batch->link, &instance->pending_batches);
     305        int err;
     306
     307        if ((err = ohci_transfer_batch_prepare(ohci_batch)))
     308                return err;
     309
     310        fibril_mutex_lock(&hc->guard);
     311        if ((err = endpoint_activate_locked(ep, batch))) {
     312                fibril_mutex_unlock(&hc->guard);
     313                return err;
     314        }
     315
    308316        ohci_transfer_batch_commit(ohci_batch);
     317        list_append(&ohci_ep->pending_link, &hc->pending_endpoints);
     318        fibril_mutex_unlock(&hc->guard);
    309319
    310320        /* Control and bulk schedules need a kick to start working */
     
    312322        {
    313323        case USB_TRANSFER_CONTROL:
    314                 OHCI_SET(instance->registers->command_status, CS_CLF);
     324                OHCI_SET(hc->registers->command_status, CS_CLF);
    315325                break;
    316326        case USB_TRANSFER_BULK:
    317                 OHCI_SET(instance->registers->command_status, CS_BLF);
     327                OHCI_SET(hc->registers->command_status, CS_BLF);
    318328                break;
    319329        default:
    320330                break;
    321331        }
    322         fibril_mutex_unlock(&instance->guard);
     332
    323333        return EOK;
    324334}
     
    329339 * @param[in] status Value of the status register at the time of interrupt.
    330340 */
    331 void ohci_hc_interrupt(hcd_t *hcd, uint32_t status)
    332 {
    333         assert(hcd);
    334         hc_t *instance = hcd_get_driver_data(hcd);
     341void ohci_hc_interrupt(bus_t *bus_base, uint32_t status)
     342{
     343        assert(bus_base);
     344
     345        ohci_bus_t *bus = (ohci_bus_t *) bus_base;
     346        hc_t *hc = bus->hc;
     347        assert(hc);
     348
    335349        status = OHCI_RD(status);
    336         assert(instance);
     350        assert(hc);
    337351        if ((status & ~I_SF) == 0) /* ignore sof status */
    338352                return;
    339         usb_log_debug2("OHCI(%p) interrupt: %x.\n", instance, status);
     353        usb_log_debug2("OHCI(%p) interrupt: %x.", hc, status);
    340354        if (status & I_RHSC)
    341                 ohci_rh_interrupt(&instance->rh);
     355                ohci_rh_interrupt(&hc->rh);
    342356
    343357        if (status & I_WDH) {
    344                 fibril_mutex_lock(&instance->guard);
    345                 usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).\n", instance->hcca,
    346                     OHCI_RD(instance->registers->hcca),
    347                     (void *) addr_to_phys(instance->hcca));
    348                 usb_log_debug2("Periodic current: %#" PRIx32 ".\n",
    349                     OHCI_RD(instance->registers->periodic_current));
    350 
    351                 link_t *current = list_first(&instance->pending_batches);
    352                 while (current && current != &instance->pending_batches.head) {
    353                         link_t *next = current->next;
    354                         ohci_transfer_batch_t *batch =
    355                             ohci_transfer_batch_from_link(current);
    356 
    357                         if (ohci_transfer_batch_is_complete(batch)) {
     358                fibril_mutex_lock(&hc->guard);
     359                usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).", hc->hcca,
     360                    OHCI_RD(hc->registers->hcca),
     361                    (void *) addr_to_phys(hc->hcca));
     362                usb_log_debug2("Periodic current: %#" PRIx32 ".",
     363                    OHCI_RD(hc->registers->periodic_current));
     364
     365                list_foreach_safe(hc->pending_endpoints, current, next) {
     366                        ohci_endpoint_t *ep
     367                                = list_get_instance(current, ohci_endpoint_t, pending_link);
     368
     369                        ohci_transfer_batch_t *batch
     370                                = ohci_transfer_batch_get(ep->base.active_batch);
     371                        assert(batch);
     372
     373                        if (ohci_transfer_batch_check_completed(batch)) {
     374                                endpoint_deactivate_locked(&ep->base);
    358375                                list_remove(current);
    359                                 ohci_transfer_batch_finish_dispose(batch);
     376                                hc_reset_toggles(&batch->base, &ohci_ep_toggle_reset);
     377                                usb_transfer_batch_finish(&batch->base);
    360378                        }
    361 
    362                         current = next;
    363379                }
    364                 fibril_mutex_unlock(&instance->guard);
     380                fibril_mutex_unlock(&hc->guard);
    365381        }
    366382
    367383        if (status & I_UE) {
    368                 usb_log_fatal("Error like no other!\n");
    369                 hc_start(instance);
     384                usb_log_fatal("Error like no other!");
     385                hc_start(&hc->base);
    370386        }
    371387
     
    379395 * @param[in] instance OHCI hc driver structure.
    380396 */
    381 void hc_gain_control(hc_t *instance)
    382 {
    383         assert(instance);
    384 
    385         usb_log_debug("Requesting OHCI control.\n");
     397int hc_gain_control(hc_device_t *hcd)
     398{
     399        hc_t *instance = hcd_to_hc(hcd);
     400
     401        usb_log_debug("Requesting OHCI control.");
    386402        if (OHCI_RD(instance->registers->revision) & R_LEGACY_FLAG) {
    387403                /* Turn off legacy emulation, it should be enough to zero
     
    392408                volatile uint32_t *ohci_emulation_reg =
    393409                (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
    394                 usb_log_debug("OHCI legacy register %p: %x.\n",
     410                usb_log_debug("OHCI legacy register %p: %x.",
    395411                    ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
    396412                /* Zero everything but A20State */
     
    398414                OHCI_CLR(*ohci_emulation_reg, ~0x100);
    399415                usb_log_debug(
    400                     "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
     416                    "OHCI legacy register (should be 0 or 0x100) %p: %x.",
    401417                    ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
    402418        }
     
    404420        /* Interrupt routing enabled => smm driver is active */
    405421        if (OHCI_RD(instance->registers->control) & C_IR) {
    406                 usb_log_debug("SMM driver: request ownership change.\n");
     422                usb_log_debug("SMM driver: request ownership change.");
    407423                // TODO: should we ack interrupts before doing this?
    408424                OHCI_SET(instance->registers->command_status, CS_OCR);
     
    411427                        async_usleep(1000);
    412428                }
    413                 usb_log_info("SMM driver: Ownership taken.\n");
     429                usb_log_info("SMM driver: Ownership taken.");
    414430                C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
    415431                async_usleep(50000);
    416                 return;
     432                return EOK;
    417433        }
    418434
     
    420436        /* Interrupt routing disabled && status != USB_RESET => BIOS active */
    421437        if (hc_status != C_HCFS_RESET) {
    422                 usb_log_debug("BIOS driver found.\n");
     438                usb_log_debug("BIOS driver found.");
    423439                if (hc_status == C_HCFS_OPERATIONAL) {
    424                         usb_log_info("BIOS driver: HC operational.\n");
    425                         return;
     440                        usb_log_info("BIOS driver: HC operational.");
     441                        return EOK;
    426442                }
    427443                /* HC is suspended assert resume for 20ms */
    428444                C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
    429445                async_usleep(20000);
    430                 usb_log_info("BIOS driver: HC resumed.\n");
    431                 return;
     446                usb_log_info("BIOS driver: HC resumed.");
     447                return EOK;
    432448        }
    433449
    434450        /* HC is in reset (hw startup) => no other driver
    435451         * maintain reset for at least the time specified in USB spec (50 ms)*/
    436         usb_log_debug("Host controller found in reset state.\n");
     452        usb_log_debug("Host controller found in reset state.");
    437453        async_usleep(50000);
     454        return EOK;
    438455}
    439456
     
    442459 * @param[in] instance OHCI hc driver structure.
    443460 */
    444 void hc_start(hc_t *instance)
    445 {
     461int hc_start(hc_device_t *hcd)
     462{
     463        hc_t *instance = hcd_to_hc(hcd);
     464        ohci_rh_init(&instance->rh, instance->registers, &instance->guard, "ohci rh");
     465
    446466        /* OHCI guide page 42 */
    447467        assert(instance);
    448         usb_log_debug2("Started hc initialization routine.\n");
     468        usb_log_debug2("Started hc initialization routine.");
    449469
    450470        /* Save contents of fm_interval register */
    451471        const uint32_t fm_interval = OHCI_RD(instance->registers->fm_interval);
    452         usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);
     472        usb_log_debug2("Old value of HcFmInterval: %x.", fm_interval);
    453473
    454474        /* Reset hc */
    455         usb_log_debug2("HC reset.\n");
     475        usb_log_debug2("HC reset.");
    456476        size_t time = 0;
    457477        OHCI_WR(instance->registers->command_status, CS_HCR);
     
    460480                time += 10;
    461481        }
    462         usb_log_debug2("HC reset complete in %zu us.\n", time);
     482        usb_log_debug2("HC reset complete in %zu us.", time);
    463483
    464484        /* Restore fm_interval */
     
    467487
    468488        /* hc is now in suspend state */
    469         usb_log_debug2("HC should be in suspend state(%x).\n",
     489        usb_log_debug2("HC should be in suspend state(%x).",
    470490            OHCI_RD(instance->registers->control));
    471491
     
    476496        OHCI_WR(instance->registers->bulk_head,
    477497            instance->lists[USB_TRANSFER_BULK].list_head_pa);
    478         usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").\n",
     498        usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").",
    479499            instance->lists[USB_TRANSFER_BULK].list_head,
    480500            instance->lists[USB_TRANSFER_BULK].list_head_pa);
     
    482502        OHCI_WR(instance->registers->control_head,
    483503            instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
    484         usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").\n",
     504        usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").",
    485505            instance->lists[USB_TRANSFER_CONTROL].list_head,
    486506            instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
     
    488508        /* Enable queues */
    489509        OHCI_SET(instance->registers->control, (C_PLE | C_IE | C_CLE | C_BLE));
    490         usb_log_debug("Queues enabled(%x).\n",
     510        usb_log_debug("Queues enabled(%x).",
    491511            OHCI_RD(instance->registers->control));
    492512
    493513        /* Enable interrupts */
    494         if (instance->hw_interrupts) {
     514        if (instance->base.irq_cap >= 0) {
    495515                OHCI_WR(instance->registers->interrupt_enable,
    496516                    OHCI_USED_INTERRUPTS);
    497                 usb_log_debug("Enabled interrupts: %x.\n",
     517                usb_log_debug("Enabled interrupts: %x.",
    498518                    OHCI_RD(instance->registers->interrupt_enable));
    499519                OHCI_WR(instance->registers->interrupt_enable, I_MI);
     
    505525        OHCI_WR(instance->registers->periodic_start,
    506526            ((frame_length / 10) * 9) & PS_MASK << PS_SHIFT);
    507         usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n",
     527        usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).",
    508528            OHCI_RD(instance->registers->periodic_start),
    509529            OHCI_RD(instance->registers->periodic_start), frame_length);
    510530        C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
    511         usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
     531        usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).",
    512532            OHCI_RD(instance->registers->control));
     533
     534        return EOK;
     535}
     536
     537/**
     538 * Setup roothub as a virtual hub.
     539 */
     540int hc_setup_roothub(hc_device_t *hcd)
     541{
     542        return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL);
    513543}
    514544
     
    526556        const errno_t ret = endpoint_list_init(&instance->lists[type], name); \
    527557        if (ret != EOK) { \
    528                 usb_log_error("Failed to setup %s endpoint list: %s.\n", \
     558                usb_log_error("Failed to setup %s endpoint list: %s.", \
    529559                    name, str_error(ret)); \
    530560                endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
     
    558588        memset(&instance->rh, 0, sizeof(instance->rh));
    559589        /* Init queues */
    560         const errno_t ret = hc_init_transfer_lists(instance);
     590        errno_t ret = hc_init_transfer_lists(instance);
    561591        if (ret != EOK) {
    562592                return ret;
     
    567597        if (instance->hcca == NULL)
    568598                return ENOMEM;
    569         usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
     599        usb_log_debug2("OHCI HCCA initialized at %p.", instance->hcca);
    570600
    571601        for (unsigned i = 0; i < HCCA_INT_EP_COUNT; ++i) {
     
    573603                    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    574604        }
    575         usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").\n",
     605        usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").",
    576606            instance->lists[USB_TRANSFER_INTERRUPT].list_head,
    577607            instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    578608
     609        if ((ret = ohci_bus_init(&instance->bus, instance))) {
     610                usb_log_error("HC(%p): Failed to setup bus : %s",
     611                    instance, str_error(ret));
     612                return ret;
     613        }
     614
     615        hc_device_setup(&instance->base, (bus_t *) &instance->bus);
     616
    579617        return EOK;
    580618}
Note: See TracChangeset for help on using the changeset viewer.