Ignore:
File:
1 edited

Legend:

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

    r68e5406 r705f83a  
    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 int hc_init_transfer_lists(hc_t *instance);
    9493static int hc_init_memory(hc_t *instance);
     
    103102 * @return Error code.
    104103 */
    105 int ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)
     104int hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
    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
    143         *irq = hw_res->irqs.irqs[0];
    144         return EOK;
     142        return hw_res->irqs.irqs[0];
    145143}
    146144
     
    152150 * @return Error code
    153151 */
    154 int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
    155 {
    156         assert(instance);
     152int hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
     153{
     154        hc_t *instance = hcd_to_hc(hcd);
    157155        assert(hw_res);
    158156        if (hw_res->mem_ranges.count != 1 ||
     
    163161            (void **) &instance->registers);
    164162        if (ret != EOK) {
    165                 usb_log_error("Failed to gain access to registers: %s.\n",
     163                usb_log_error("Failed to gain access to registers: %s.",
    166164                    str_error(ret));
    167165                return ret;
    168166        }
    169         usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n",
     167        usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.",
    170168            hw_res->mem_ranges.ranges[0].address.absolute,
    171169            hw_res->mem_ranges.ranges[0].size);
    172170
    173         list_initialize(&instance->pending_batches);
     171        list_initialize(&instance->pending_endpoints);
    174172        fibril_mutex_initialize(&instance->guard);
    175         instance->hw_interrupts = interrupts;
    176173
    177174        ret = hc_init_memory(instance);
    178175        if (ret != EOK) {
    179                 usb_log_error("Failed to create OHCI memory structures: %s.\n",
     176                usb_log_error("Failed to create OHCI memory structures: %s.",
    180177                    str_error(ret));
    181178                // TODO: We should disable pio access here
     
    183180        }
    184181
    185         hc_gain_control(instance);
    186 
    187         ohci_rh_init(&instance->rh, instance->registers, "ohci rh");
    188         hc_start(instance);
    189 
    190182        return EOK;
    191183}
     
    195187 * @param[in] instance Host controller structure to use.
    196188 */
    197 void hc_fini(hc_t *instance)
     189int hc_gone(hc_device_t *instance)
    198190{
    199191        assert(instance);
    200192        /* TODO: implement*/
    201 };
     193        return ENOTSUP;
     194}
    202195
    203196void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)
     
    269262}
    270263
    271 int ohci_hc_status(hcd_t *hcd, uint32_t *status)
    272 {
    273         assert(hcd);
     264int ohci_hc_status(bus_t *bus_base, uint32_t *status)
     265{
     266        assert(bus_base);
    274267        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);
     268
     269        ohci_bus_t *bus = (ohci_bus_t *) bus_base;
     270        hc_t *hc = bus->hc;
     271        assert(hc);
     272
     273        if (hc->registers){
     274                *status = OHCI_RD(hc->registers->interrupt_status);
     275                OHCI_WR(hc->registers->interrupt_status, *status);
    281276        }
    282277        return EOK;
     
    289284 * @return Error code.
    290285 */
    291 int 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);
     286int ohci_hc_schedule(usb_transfer_batch_t *batch)
     287{
     288        assert(batch);
     289
     290        ohci_bus_t *bus = (ohci_bus_t *) endpoint_get_bus(batch->ep);
     291        hc_t *hc = bus->hc;
     292        assert(hc);
    296293
    297294        /* 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         }
     295        if (batch->target.address == ohci_rh_get_address(&hc->rh)) {
     296                usb_log_debug("OHCI root hub request.");
     297                return ohci_rh_schedule(&hc->rh, batch);
     298        }
     299
     300        endpoint_t *ep = batch->ep;
     301        ohci_endpoint_t * const ohci_ep = ohci_endpoint_get(ep);
    302302        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);
     303        int err;
     304
     305        fibril_mutex_lock(&hc->guard);
     306        if ((err = endpoint_activate_locked(ep, batch))) {
     307                fibril_mutex_unlock(&hc->guard);
     308                return err;
     309        }
     310
     311        if ((err = ohci_transfer_batch_prepare(ohci_batch)))
     312                return err;
     313
    308314        ohci_transfer_batch_commit(ohci_batch);
     315        list_append(&ohci_ep->pending_link, &hc->pending_endpoints);
     316        fibril_mutex_unlock(&hc->guard);
    309317
    310318        /* Control and bulk schedules need a kick to start working */
     
    312320        {
    313321        case USB_TRANSFER_CONTROL:
    314                 OHCI_SET(instance->registers->command_status, CS_CLF);
     322                OHCI_SET(hc->registers->command_status, CS_CLF);
    315323                break;
    316324        case USB_TRANSFER_BULK:
    317                 OHCI_SET(instance->registers->command_status, CS_BLF);
     325                OHCI_SET(hc->registers->command_status, CS_BLF);
    318326                break;
    319327        default:
    320328                break;
    321329        }
    322         fibril_mutex_unlock(&instance->guard);
     330
    323331        return EOK;
    324332}
     
    329337 * @param[in] status Value of the status register at the time of interrupt.
    330338 */
    331 void ohci_hc_interrupt(hcd_t *hcd, uint32_t status)
    332 {
    333         assert(hcd);
    334         hc_t *instance = hcd_get_driver_data(hcd);
     339void ohci_hc_interrupt(bus_t *bus_base, uint32_t status)
     340{
     341        assert(bus_base);
     342
     343        ohci_bus_t *bus = (ohci_bus_t *) bus_base;
     344        hc_t *hc = bus->hc;
     345        assert(hc);
     346
    335347        status = OHCI_RD(status);
    336         assert(instance);
     348        assert(hc);
    337349        if ((status & ~I_SF) == 0) /* ignore sof status */
    338350                return;
    339         usb_log_debug2("OHCI(%p) interrupt: %x.\n", instance, status);
     351        usb_log_debug2("OHCI(%p) interrupt: %x.", hc, status);
    340352        if (status & I_RHSC)
    341                 ohci_rh_interrupt(&instance->rh);
     353                ohci_rh_interrupt(&hc->rh);
    342354
    343355        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)) {
     356                fibril_mutex_lock(&hc->guard);
     357                usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).", hc->hcca,
     358                    OHCI_RD(hc->registers->hcca),
     359                    (void *) addr_to_phys(hc->hcca));
     360                usb_log_debug2("Periodic current: %#" PRIx32 ".",
     361                    OHCI_RD(hc->registers->periodic_current));
     362
     363                list_foreach_safe(hc->pending_endpoints, current, next) {
     364                        ohci_endpoint_t *ep
     365                                = list_get_instance(current, ohci_endpoint_t, pending_link);
     366
     367                        ohci_transfer_batch_t *batch
     368                                = ohci_transfer_batch_get(ep->base.active_batch);
     369                        assert(batch);
     370
     371                        if (ohci_transfer_batch_check_completed(batch)) {
     372                                endpoint_deactivate_locked(&ep->base);
    358373                                list_remove(current);
    359                                 ohci_transfer_batch_finish_dispose(batch);
     374                                hc_reset_toggles(&batch->base, &ohci_ep_toggle_reset);
     375                                usb_transfer_batch_finish(&batch->base);
    360376                        }
    361 
    362                         current = next;
    363377                }
    364                 fibril_mutex_unlock(&instance->guard);
     378                fibril_mutex_unlock(&hc->guard);
    365379        }
    366380
    367381        if (status & I_UE) {
    368                 usb_log_fatal("Error like no other!\n");
    369                 hc_start(instance);
     382                usb_log_fatal("Error like no other!");
     383                hc_start(&hc->base);
    370384        }
    371385
     
    379393 * @param[in] instance OHCI hc driver structure.
    380394 */
    381 void hc_gain_control(hc_t *instance)
    382 {
    383         assert(instance);
    384 
    385         usb_log_debug("Requesting OHCI control.\n");
     395int hc_gain_control(hc_device_t *hcd)
     396{
     397        hc_t *instance = hcd_to_hc(hcd);
     398
     399        usb_log_debug("Requesting OHCI control.");
    386400        if (OHCI_RD(instance->registers->revision) & R_LEGACY_FLAG) {
    387401                /* Turn off legacy emulation, it should be enough to zero
     
    392406                volatile uint32_t *ohci_emulation_reg =
    393407                (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
    394                 usb_log_debug("OHCI legacy register %p: %x.\n",
     408                usb_log_debug("OHCI legacy register %p: %x.",
    395409                    ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
    396410                /* Zero everything but A20State */
     
    398412                OHCI_CLR(*ohci_emulation_reg, ~0x100);
    399413                usb_log_debug(
    400                     "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
     414                    "OHCI legacy register (should be 0 or 0x100) %p: %x.",
    401415                    ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
    402416        }
     
    404418        /* Interrupt routing enabled => smm driver is active */
    405419        if (OHCI_RD(instance->registers->control) & C_IR) {
    406                 usb_log_debug("SMM driver: request ownership change.\n");
     420                usb_log_debug("SMM driver: request ownership change.");
    407421                // TODO: should we ack interrupts before doing this?
    408422                OHCI_SET(instance->registers->command_status, CS_OCR);
     
    411425                        async_usleep(1000);
    412426                }
    413                 usb_log_info("SMM driver: Ownership taken.\n");
     427                usb_log_info("SMM driver: Ownership taken.");
    414428                C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
    415429                async_usleep(50000);
    416                 return;
     430                return EOK;
    417431        }
    418432
     
    420434        /* Interrupt routing disabled && status != USB_RESET => BIOS active */
    421435        if (hc_status != C_HCFS_RESET) {
    422                 usb_log_debug("BIOS driver found.\n");
     436                usb_log_debug("BIOS driver found.");
    423437                if (hc_status == C_HCFS_OPERATIONAL) {
    424                         usb_log_info("BIOS driver: HC operational.\n");
    425                         return;
     438                        usb_log_info("BIOS driver: HC operational.");
     439                        return EOK;
    426440                }
    427441                /* HC is suspended assert resume for 20ms */
    428442                C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
    429443                async_usleep(20000);
    430                 usb_log_info("BIOS driver: HC resumed.\n");
    431                 return;
     444                usb_log_info("BIOS driver: HC resumed.");
     445                return EOK;
    432446        }
    433447
    434448        /* HC is in reset (hw startup) => no other driver
    435449         * maintain reset for at least the time specified in USB spec (50 ms)*/
    436         usb_log_debug("Host controller found in reset state.\n");
     450        usb_log_debug("Host controller found in reset state.");
    437451        async_usleep(50000);
     452        return EOK;
    438453}
    439454
     
    442457 * @param[in] instance OHCI hc driver structure.
    443458 */
    444 void hc_start(hc_t *instance)
    445 {
     459int hc_start(hc_device_t *hcd)
     460{
     461        hc_t *instance = hcd_to_hc(hcd);
     462        ohci_rh_init(&instance->rh, instance->registers, &instance->guard, "ohci rh");
     463
    446464        /* OHCI guide page 42 */
    447465        assert(instance);
    448         usb_log_debug2("Started hc initialization routine.\n");
     466        usb_log_debug2("Started hc initialization routine.");
    449467
    450468        /* Save contents of fm_interval register */
    451469        const uint32_t fm_interval = OHCI_RD(instance->registers->fm_interval);
    452         usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);
     470        usb_log_debug2("Old value of HcFmInterval: %x.", fm_interval);
    453471
    454472        /* Reset hc */
    455         usb_log_debug2("HC reset.\n");
     473        usb_log_debug2("HC reset.");
    456474        size_t time = 0;
    457475        OHCI_WR(instance->registers->command_status, CS_HCR);
     
    460478                time += 10;
    461479        }
    462         usb_log_debug2("HC reset complete in %zu us.\n", time);
     480        usb_log_debug2("HC reset complete in %zu us.", time);
    463481
    464482        /* Restore fm_interval */
     
    467485
    468486        /* hc is now in suspend state */
    469         usb_log_debug2("HC should be in suspend state(%x).\n",
     487        usb_log_debug2("HC should be in suspend state(%x).",
    470488            OHCI_RD(instance->registers->control));
    471489
     
    476494        OHCI_WR(instance->registers->bulk_head,
    477495            instance->lists[USB_TRANSFER_BULK].list_head_pa);
    478         usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").\n",
     496        usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").",
    479497            instance->lists[USB_TRANSFER_BULK].list_head,
    480498            instance->lists[USB_TRANSFER_BULK].list_head_pa);
     
    482500        OHCI_WR(instance->registers->control_head,
    483501            instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
    484         usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").\n",
     502        usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").",
    485503            instance->lists[USB_TRANSFER_CONTROL].list_head,
    486504            instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
     
    488506        /* Enable queues */
    489507        OHCI_SET(instance->registers->control, (C_PLE | C_IE | C_CLE | C_BLE));
    490         usb_log_debug("Queues enabled(%x).\n",
     508        usb_log_debug("Queues enabled(%x).",
    491509            OHCI_RD(instance->registers->control));
    492510
    493511        /* Enable interrupts */
    494         if (instance->hw_interrupts) {
     512        if (instance->base.irq_cap >= 0) {
    495513                OHCI_WR(instance->registers->interrupt_enable,
    496514                    OHCI_USED_INTERRUPTS);
    497                 usb_log_debug("Enabled interrupts: %x.\n",
     515                usb_log_debug("Enabled interrupts: %x.",
    498516                    OHCI_RD(instance->registers->interrupt_enable));
    499517                OHCI_WR(instance->registers->interrupt_enable, I_MI);
     
    505523        OHCI_WR(instance->registers->periodic_start,
    506524            ((frame_length / 10) * 9) & PS_MASK << PS_SHIFT);
    507         usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n",
     525        usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).",
    508526            OHCI_RD(instance->registers->periodic_start),
    509527            OHCI_RD(instance->registers->periodic_start), frame_length);
    510528        C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
    511         usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
     529        usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).",
    512530            OHCI_RD(instance->registers->control));
     531
     532        return EOK;
     533}
     534
     535/**
     536 * Setup roothub as a virtual hub.
     537 */
     538int hc_setup_roothub(hc_device_t *hcd)
     539{
     540        return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL);
    513541}
    514542
     
    526554        const int ret = endpoint_list_init(&instance->lists[type], name); \
    527555        if (ret != EOK) { \
    528                 usb_log_error("Failed to setup %s endpoint list: %s.\n", \
     556                usb_log_error("Failed to setup %s endpoint list: %s.", \
    529557                    name, str_error(ret)); \
    530558                endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
     
    558586        memset(&instance->rh, 0, sizeof(instance->rh));
    559587        /* Init queues */
    560         const int ret = hc_init_transfer_lists(instance);
     588        int ret = hc_init_transfer_lists(instance);
    561589        if (ret != EOK) {
    562590                return ret;
     
    567595        if (instance->hcca == NULL)
    568596                return ENOMEM;
    569         usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
     597        usb_log_debug2("OHCI HCCA initialized at %p.", instance->hcca);
    570598
    571599        for (unsigned i = 0; i < HCCA_INT_EP_COUNT; ++i) {
     
    573601                    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    574602        }
    575         usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").\n",
     603        usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").",
    576604            instance->lists[USB_TRANSFER_INTERRUPT].list_head,
    577605            instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    578606
     607        if ((ret = ohci_bus_init(&instance->bus, instance))) {
     608                usb_log_error("HC(%p): Failed to setup bus : %s",
     609                    instance, str_error(ret));
     610                return ret;
     611        }
     612
     613        hc_device_setup(&instance->base, (bus_t *) &instance->bus);
     614
    579615        return EOK;
    580616}
Note: See TracChangeset for help on using the changeset viewer.