Ignore:
File:
1 edited

Legend:

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

    rb7fd2a0 r5a6cc679  
    4545
    4646#include <usb/debug.h>
     47#include <usb/host/utility.h>
    4748#include <usb/usb.h>
    4849
    49 #include "ohci_endpoint.h"
     50#include "ohci_bus.h"
    5051#include "ohci_batch.h"
    5152
     
    8990};
    9091
    91 static void hc_gain_control(hc_t *instance);
    92 static void hc_start(hc_t *instance);
    9392static errno_t hc_init_transfer_lists(hc_t *instance);
    9493static errno_t hc_init_memory(hc_t *instance);
     
    103102 * @return Error code.
    104103 */
    105 errno_t ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)
     104errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
    106105{
    107106        assert(code);
     
    138137        OHCI_WR(code->cmds[1].value, OHCI_USED_INTERRUPTS);
    139138
    140         usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n",
     139        usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.",
    141140            RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
    142141
     
    152151 * @return Error code
    153152 */
    154 errno_t hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
    155 {
    156         assert(instance);
     153errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
     154{
     155        hc_t *instance = hcd_to_hc(hcd);
    157156        assert(hw_res);
    158157        if (hw_res->mem_ranges.count != 1 ||
     
    163162            (void **) &instance->registers);
    164163        if (ret != EOK) {
    165                 usb_log_error("Failed to gain access to registers: %s.\n",
     164                usb_log_error("Failed to gain access to registers: %s.",
    166165                    str_error(ret));
    167166                return ret;
    168167        }
    169         usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n",
     168        usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.",
    170169            hw_res->mem_ranges.ranges[0].address.absolute,
    171170            hw_res->mem_ranges.ranges[0].size);
    172171
    173         list_initialize(&instance->pending_batches);
     172        list_initialize(&instance->pending_endpoints);
    174173        fibril_mutex_initialize(&instance->guard);
    175         instance->hw_interrupts = interrupts;
    176174
    177175        ret = hc_init_memory(instance);
    178176        if (ret != EOK) {
    179                 usb_log_error("Failed to create OHCI memory structures: %s.\n",
     177                usb_log_error("Failed to create OHCI memory structures: %s.",
    180178                    str_error(ret));
    181179                // TODO: We should disable pio access here
     
    183181        }
    184182
    185         hc_gain_control(instance);
    186 
    187         ohci_rh_init(&instance->rh, instance->registers, "ohci rh");
    188         hc_start(instance);
    189 
    190183        return EOK;
    191184}
     
    195188 * @param[in] instance Host controller structure to use.
    196189 */
    197 void hc_fini(hc_t *instance)
     190int hc_gone(hc_device_t *instance)
    198191{
    199192        assert(instance);
    200193        /* TODO: implement*/
    201 };
     194        return ENOTSUP;
     195}
    202196
    203197void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)
     
    269263}
    270264
    271 errno_t ohci_hc_status(hcd_t *hcd, uint32_t *status)
    272 {
    273         assert(hcd);
     265errno_t ohci_hc_status(bus_t *bus_base, uint32_t *status)
     266{
     267        assert(bus_base);
    274268        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);
     269
     270        ohci_bus_t *bus = (ohci_bus_t *) bus_base;
     271        hc_t *hc = bus->hc;
     272        assert(hc);
     273
     274        if (hc->registers){
     275                *status = OHCI_RD(hc->registers->interrupt_status);
     276                OHCI_WR(hc->registers->interrupt_status, *status);
    281277        }
    282278        return EOK;
     
    289285 * @return Error code.
    290286 */
    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);
     287errno_t ohci_hc_schedule(usb_transfer_batch_t *batch)
     288{
     289        assert(batch);
     290
     291        ohci_bus_t *bus = (ohci_bus_t *) endpoint_get_bus(batch->ep);
     292        hc_t *hc = bus->hc;
     293        assert(hc);
    296294
    297295        /* 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         }
     296        if (batch->target.address == ohci_rh_get_address(&hc->rh)) {
     297                usb_log_debug("OHCI root hub request.");
     298                return ohci_rh_schedule(&hc->rh, batch);
     299        }
     300
     301        endpoint_t *ep = batch->ep;
     302        ohci_endpoint_t * const ohci_ep = ohci_endpoint_get(ep);
    302303        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);
     304        int err;
     305
     306        fibril_mutex_lock(&hc->guard);
     307        if ((err = endpoint_activate_locked(ep, batch))) {
     308                fibril_mutex_unlock(&hc->guard);
     309                return err;
     310        }
     311
     312        if ((err = ohci_transfer_batch_prepare(ohci_batch)))
     313                return err;
     314
    308315        ohci_transfer_batch_commit(ohci_batch);
     316        list_append(&ohci_ep->pending_link, &hc->pending_endpoints);
     317        fibril_mutex_unlock(&hc->guard);
    309318
    310319        /* Control and bulk schedules need a kick to start working */
     
    312321        {
    313322        case USB_TRANSFER_CONTROL:
    314                 OHCI_SET(instance->registers->command_status, CS_CLF);
     323                OHCI_SET(hc->registers->command_status, CS_CLF);
    315324                break;
    316325        case USB_TRANSFER_BULK:
    317                 OHCI_SET(instance->registers->command_status, CS_BLF);
     326                OHCI_SET(hc->registers->command_status, CS_BLF);
    318327                break;
    319328        default:
    320329                break;
    321330        }
    322         fibril_mutex_unlock(&instance->guard);
     331
    323332        return EOK;
    324333}
     
    329338 * @param[in] status Value of the status register at the time of interrupt.
    330339 */
    331 void ohci_hc_interrupt(hcd_t *hcd, uint32_t status)
    332 {
    333         assert(hcd);
    334         hc_t *instance = hcd_get_driver_data(hcd);
     340void ohci_hc_interrupt(bus_t *bus_base, uint32_t status)
     341{
     342        assert(bus_base);
     343
     344        ohci_bus_t *bus = (ohci_bus_t *) bus_base;
     345        hc_t *hc = bus->hc;
     346        assert(hc);
     347
    335348        status = OHCI_RD(status);
    336         assert(instance);
     349        assert(hc);
    337350        if ((status & ~I_SF) == 0) /* ignore sof status */
    338351                return;
    339         usb_log_debug2("OHCI(%p) interrupt: %x.\n", instance, status);
     352        usb_log_debug2("OHCI(%p) interrupt: %x.", hc, status);
    340353        if (status & I_RHSC)
    341                 ohci_rh_interrupt(&instance->rh);
     354                ohci_rh_interrupt(&hc->rh);
    342355
    343356        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)) {
     357                fibril_mutex_lock(&hc->guard);
     358                usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).", hc->hcca,
     359                    OHCI_RD(hc->registers->hcca),
     360                    (void *) addr_to_phys(hc->hcca));
     361                usb_log_debug2("Periodic current: %#" PRIx32 ".",
     362                    OHCI_RD(hc->registers->periodic_current));
     363
     364                list_foreach_safe(hc->pending_endpoints, current, next) {
     365                        ohci_endpoint_t *ep
     366                                = list_get_instance(current, ohci_endpoint_t, pending_link);
     367
     368                        ohci_transfer_batch_t *batch
     369                                = ohci_transfer_batch_get(ep->base.active_batch);
     370                        assert(batch);
     371
     372                        if (ohci_transfer_batch_check_completed(batch)) {
     373                                endpoint_deactivate_locked(&ep->base);
    358374                                list_remove(current);
    359                                 ohci_transfer_batch_finish_dispose(batch);
     375                                hc_reset_toggles(&batch->base, &ohci_ep_toggle_reset);
     376                                usb_transfer_batch_finish(&batch->base);
    360377                        }
    361 
    362                         current = next;
    363378                }
    364                 fibril_mutex_unlock(&instance->guard);
     379                fibril_mutex_unlock(&hc->guard);
    365380        }
    366381
    367382        if (status & I_UE) {
    368                 usb_log_fatal("Error like no other!\n");
    369                 hc_start(instance);
     383                usb_log_fatal("Error like no other!");
     384                hc_start(&hc->base);
    370385        }
    371386
     
    379394 * @param[in] instance OHCI hc driver structure.
    380395 */
    381 void hc_gain_control(hc_t *instance)
    382 {
    383         assert(instance);
    384 
    385         usb_log_debug("Requesting OHCI control.\n");
     396int hc_gain_control(hc_device_t *hcd)
     397{
     398        hc_t *instance = hcd_to_hc(hcd);
     399
     400        usb_log_debug("Requesting OHCI control.");
    386401        if (OHCI_RD(instance->registers->revision) & R_LEGACY_FLAG) {
    387402                /* Turn off legacy emulation, it should be enough to zero
     
    392407                volatile uint32_t *ohci_emulation_reg =
    393408                (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
    394                 usb_log_debug("OHCI legacy register %p: %x.\n",
     409                usb_log_debug("OHCI legacy register %p: %x.",
    395410                    ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
    396411                /* Zero everything but A20State */
     
    398413                OHCI_CLR(*ohci_emulation_reg, ~0x100);
    399414                usb_log_debug(
    400                     "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
     415                    "OHCI legacy register (should be 0 or 0x100) %p: %x.",
    401416                    ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
    402417        }
     
    404419        /* Interrupt routing enabled => smm driver is active */
    405420        if (OHCI_RD(instance->registers->control) & C_IR) {
    406                 usb_log_debug("SMM driver: request ownership change.\n");
     421                usb_log_debug("SMM driver: request ownership change.");
    407422                // TODO: should we ack interrupts before doing this?
    408423                OHCI_SET(instance->registers->command_status, CS_OCR);
     
    411426                        async_usleep(1000);
    412427                }
    413                 usb_log_info("SMM driver: Ownership taken.\n");
     428                usb_log_info("SMM driver: Ownership taken.");
    414429                C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
    415430                async_usleep(50000);
    416                 return;
     431                return EOK;
    417432        }
    418433
     
    420435        /* Interrupt routing disabled && status != USB_RESET => BIOS active */
    421436        if (hc_status != C_HCFS_RESET) {
    422                 usb_log_debug("BIOS driver found.\n");
     437                usb_log_debug("BIOS driver found.");
    423438                if (hc_status == C_HCFS_OPERATIONAL) {
    424                         usb_log_info("BIOS driver: HC operational.\n");
    425                         return;
     439                        usb_log_info("BIOS driver: HC operational.");
     440                        return EOK;
    426441                }
    427442                /* HC is suspended assert resume for 20ms */
    428443                C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
    429444                async_usleep(20000);
    430                 usb_log_info("BIOS driver: HC resumed.\n");
    431                 return;
     445                usb_log_info("BIOS driver: HC resumed.");
     446                return EOK;
    432447        }
    433448
    434449        /* HC is in reset (hw startup) => no other driver
    435450         * maintain reset for at least the time specified in USB spec (50 ms)*/
    436         usb_log_debug("Host controller found in reset state.\n");
     451        usb_log_debug("Host controller found in reset state.");
    437452        async_usleep(50000);
     453        return EOK;
    438454}
    439455
     
    442458 * @param[in] instance OHCI hc driver structure.
    443459 */
    444 void hc_start(hc_t *instance)
    445 {
     460int hc_start(hc_device_t *hcd)
     461{
     462        hc_t *instance = hcd_to_hc(hcd);
     463        ohci_rh_init(&instance->rh, instance->registers, &instance->guard, "ohci rh");
     464
    446465        /* OHCI guide page 42 */
    447466        assert(instance);
    448         usb_log_debug2("Started hc initialization routine.\n");
     467        usb_log_debug2("Started hc initialization routine.");
    449468
    450469        /* Save contents of fm_interval register */
    451470        const uint32_t fm_interval = OHCI_RD(instance->registers->fm_interval);
    452         usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);
     471        usb_log_debug2("Old value of HcFmInterval: %x.", fm_interval);
    453472
    454473        /* Reset hc */
    455         usb_log_debug2("HC reset.\n");
     474        usb_log_debug2("HC reset.");
    456475        size_t time = 0;
    457476        OHCI_WR(instance->registers->command_status, CS_HCR);
     
    460479                time += 10;
    461480        }
    462         usb_log_debug2("HC reset complete in %zu us.\n", time);
     481        usb_log_debug2("HC reset complete in %zu us.", time);
    463482
    464483        /* Restore fm_interval */
     
    467486
    468487        /* hc is now in suspend state */
    469         usb_log_debug2("HC should be in suspend state(%x).\n",
     488        usb_log_debug2("HC should be in suspend state(%x).",
    470489            OHCI_RD(instance->registers->control));
    471490
     
    476495        OHCI_WR(instance->registers->bulk_head,
    477496            instance->lists[USB_TRANSFER_BULK].list_head_pa);
    478         usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").\n",
     497        usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").",
    479498            instance->lists[USB_TRANSFER_BULK].list_head,
    480499            instance->lists[USB_TRANSFER_BULK].list_head_pa);
     
    482501        OHCI_WR(instance->registers->control_head,
    483502            instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
    484         usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").\n",
     503        usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").",
    485504            instance->lists[USB_TRANSFER_CONTROL].list_head,
    486505            instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
     
    488507        /* Enable queues */
    489508        OHCI_SET(instance->registers->control, (C_PLE | C_IE | C_CLE | C_BLE));
    490         usb_log_debug("Queues enabled(%x).\n",
     509        usb_log_debug("Queues enabled(%x).",
    491510            OHCI_RD(instance->registers->control));
    492511
    493512        /* Enable interrupts */
    494         if (instance->hw_interrupts) {
     513        if (instance->base.irq_cap >= 0) {
    495514                OHCI_WR(instance->registers->interrupt_enable,
    496515                    OHCI_USED_INTERRUPTS);
    497                 usb_log_debug("Enabled interrupts: %x.\n",
     516                usb_log_debug("Enabled interrupts: %x.",
    498517                    OHCI_RD(instance->registers->interrupt_enable));
    499518                OHCI_WR(instance->registers->interrupt_enable, I_MI);
     
    505524        OHCI_WR(instance->registers->periodic_start,
    506525            ((frame_length / 10) * 9) & PS_MASK << PS_SHIFT);
    507         usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n",
     526        usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).",
    508527            OHCI_RD(instance->registers->periodic_start),
    509528            OHCI_RD(instance->registers->periodic_start), frame_length);
    510529        C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
    511         usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
     530        usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).",
    512531            OHCI_RD(instance->registers->control));
     532
     533        return EOK;
     534}
     535
     536/**
     537 * Setup roothub as a virtual hub.
     538 */
     539int hc_setup_roothub(hc_device_t *hcd)
     540{
     541        return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL);
    513542}
    514543
     
    526555        const errno_t ret = endpoint_list_init(&instance->lists[type], name); \
    527556        if (ret != EOK) { \
    528                 usb_log_error("Failed to setup %s endpoint list: %s.\n", \
     557                usb_log_error("Failed to setup %s endpoint list: %s.", \
    529558                    name, str_error(ret)); \
    530559                endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
     
    558587        memset(&instance->rh, 0, sizeof(instance->rh));
    559588        /* Init queues */
    560         const errno_t ret = hc_init_transfer_lists(instance);
     589        errno_t ret = hc_init_transfer_lists(instance);
    561590        if (ret != EOK) {
    562591                return ret;
     
    567596        if (instance->hcca == NULL)
    568597                return ENOMEM;
    569         usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
     598        usb_log_debug2("OHCI HCCA initialized at %p.", instance->hcca);
    570599
    571600        for (unsigned i = 0; i < HCCA_INT_EP_COUNT; ++i) {
     
    573602                    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    574603        }
    575         usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").\n",
     604        usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").",
    576605            instance->lists[USB_TRANSFER_INTERRUPT].list_head,
    577606            instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    578607
     608        if ((ret = ohci_bus_init(&instance->bus, instance))) {
     609                usb_log_error("HC(%p): Failed to setup bus : %s",
     610                    instance, str_error(ret));
     611                return ret;
     612        }
     613
     614        hc_device_setup(&instance->base, (bus_t *) &instance->bus);
     615
    579616        return EOK;
    580617}
Note: See TracChangeset for help on using the changeset viewer.