Ignore:
File:
1 edited

Legend:

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

    r5a6cc679 rb7fd2a0  
    4545
    4646#include <usb/debug.h>
    47 #include <usb/host/utility.h>
    4847#include <usb/usb.h>
    4948
    50 #include "ohci_bus.h"
     49#include "ohci_endpoint.h"
    5150#include "ohci_batch.h"
    5251
     
    9089};
    9190
     91static void hc_gain_control(hc_t *instance);
     92static void hc_start(hc_t *instance);
    9293static errno_t hc_init_transfer_lists(hc_t *instance);
    9394static errno_t hc_init_memory(hc_t *instance);
     
    102103 * @return Error code.
    103104 */
    104 errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
     105errno_t ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)
    105106{
    106107        assert(code);
     
    137138        OHCI_WR(code->cmds[1].value, OHCI_USED_INTERRUPTS);
    138139
    139         usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.",
     140        usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n",
    140141            RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
    141142
     
    151152 * @return Error code
    152153 */
    153 errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
    154 {
    155         hc_t *instance = hcd_to_hc(hcd);
     154errno_t hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
     155{
     156        assert(instance);
    156157        assert(hw_res);
    157158        if (hw_res->mem_ranges.count != 1 ||
     
    162163            (void **) &instance->registers);
    163164        if (ret != EOK) {
    164                 usb_log_error("Failed to gain access to registers: %s.",
     165                usb_log_error("Failed to gain access to registers: %s.\n",
    165166                    str_error(ret));
    166167                return ret;
    167168        }
    168         usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.",
     169        usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n",
    169170            hw_res->mem_ranges.ranges[0].address.absolute,
    170171            hw_res->mem_ranges.ranges[0].size);
    171172
    172         list_initialize(&instance->pending_endpoints);
     173        list_initialize(&instance->pending_batches);
    173174        fibril_mutex_initialize(&instance->guard);
     175        instance->hw_interrupts = interrupts;
    174176
    175177        ret = hc_init_memory(instance);
    176178        if (ret != EOK) {
    177                 usb_log_error("Failed to create OHCI memory structures: %s.",
     179                usb_log_error("Failed to create OHCI memory structures: %s.\n",
    178180                    str_error(ret));
    179181                // TODO: We should disable pio access here
     
    181183        }
    182184
     185        hc_gain_control(instance);
     186
     187        ohci_rh_init(&instance->rh, instance->registers, "ohci rh");
     188        hc_start(instance);
     189
    183190        return EOK;
    184191}
     
    188195 * @param[in] instance Host controller structure to use.
    189196 */
    190 int hc_gone(hc_device_t *instance)
     197void hc_fini(hc_t *instance)
    191198{
    192199        assert(instance);
    193200        /* TODO: implement*/
    194         return ENOTSUP;
    195 }
     201};
    196202
    197203void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)
     
    263269}
    264270
    265 errno_t ohci_hc_status(bus_t *bus_base, uint32_t *status)
    266 {
    267         assert(bus_base);
     271errno_t ohci_hc_status(hcd_t *hcd, uint32_t *status)
     272{
     273        assert(hcd);
    268274        assert(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);
     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);
    277281        }
    278282        return EOK;
     
    285289 * @return Error code.
    286290 */
    287 errno_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);
     291errno_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);
    294296
    295297        /* Check for root hub communication */
    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);
     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        }
    303302        ohci_transfer_batch_t *ohci_batch = ohci_transfer_batch_get(batch);
    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 
     303        if (!ohci_batch)
     304                return ENOMEM;
     305
     306        fibril_mutex_lock(&instance->guard);
     307        list_append(&ohci_batch->link, &instance->pending_batches);
    315308        ohci_transfer_batch_commit(ohci_batch);
    316         list_append(&ohci_ep->pending_link, &hc->pending_endpoints);
    317         fibril_mutex_unlock(&hc->guard);
    318309
    319310        /* Control and bulk schedules need a kick to start working */
     
    321312        {
    322313        case USB_TRANSFER_CONTROL:
    323                 OHCI_SET(hc->registers->command_status, CS_CLF);
     314                OHCI_SET(instance->registers->command_status, CS_CLF);
    324315                break;
    325316        case USB_TRANSFER_BULK:
    326                 OHCI_SET(hc->registers->command_status, CS_BLF);
     317                OHCI_SET(instance->registers->command_status, CS_BLF);
    327318                break;
    328319        default:
    329320                break;
    330321        }
    331 
     322        fibril_mutex_unlock(&instance->guard);
    332323        return EOK;
    333324}
     
    338329 * @param[in] status Value of the status register at the time of interrupt.
    339330 */
    340 void 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 
     331void ohci_hc_interrupt(hcd_t *hcd, uint32_t status)
     332{
     333        assert(hcd);
     334        hc_t *instance = hcd_get_driver_data(hcd);
    348335        status = OHCI_RD(status);
    349         assert(hc);
     336        assert(instance);
    350337        if ((status & ~I_SF) == 0) /* ignore sof status */
    351338                return;
    352         usb_log_debug2("OHCI(%p) interrupt: %x.", hc, status);
     339        usb_log_debug2("OHCI(%p) interrupt: %x.\n", instance, status);
    353340        if (status & I_RHSC)
    354                 ohci_rh_interrupt(&hc->rh);
     341                ohci_rh_interrupt(&instance->rh);
    355342
    356343        if (status & I_WDH) {
    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);
     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)) {
    374358                                list_remove(current);
    375                                 hc_reset_toggles(&batch->base, &ohci_ep_toggle_reset);
    376                                 usb_transfer_batch_finish(&batch->base);
     359                                ohci_transfer_batch_finish_dispose(batch);
    377360                        }
     361
     362                        current = next;
    378363                }
    379                 fibril_mutex_unlock(&hc->guard);
     364                fibril_mutex_unlock(&instance->guard);
    380365        }
    381366
    382367        if (status & I_UE) {
    383                 usb_log_fatal("Error like no other!");
    384                 hc_start(&hc->base);
     368                usb_log_fatal("Error like no other!\n");
     369                hc_start(instance);
    385370        }
    386371
     
    394379 * @param[in] instance OHCI hc driver structure.
    395380 */
    396 int hc_gain_control(hc_device_t *hcd)
    397 {
    398         hc_t *instance = hcd_to_hc(hcd);
    399 
    400         usb_log_debug("Requesting OHCI control.");
     381void hc_gain_control(hc_t *instance)
     382{
     383        assert(instance);
     384
     385        usb_log_debug("Requesting OHCI control.\n");
    401386        if (OHCI_RD(instance->registers->revision) & R_LEGACY_FLAG) {
    402387                /* Turn off legacy emulation, it should be enough to zero
     
    407392                volatile uint32_t *ohci_emulation_reg =
    408393                (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
    409                 usb_log_debug("OHCI legacy register %p: %x.",
     394                usb_log_debug("OHCI legacy register %p: %x.\n",
    410395                    ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
    411396                /* Zero everything but A20State */
     
    413398                OHCI_CLR(*ohci_emulation_reg, ~0x100);
    414399                usb_log_debug(
    415                     "OHCI legacy register (should be 0 or 0x100) %p: %x.",
     400                    "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
    416401                    ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
    417402        }
     
    419404        /* Interrupt routing enabled => smm driver is active */
    420405        if (OHCI_RD(instance->registers->control) & C_IR) {
    421                 usb_log_debug("SMM driver: request ownership change.");
     406                usb_log_debug("SMM driver: request ownership change.\n");
    422407                // TODO: should we ack interrupts before doing this?
    423408                OHCI_SET(instance->registers->command_status, CS_OCR);
     
    426411                        async_usleep(1000);
    427412                }
    428                 usb_log_info("SMM driver: Ownership taken.");
     413                usb_log_info("SMM driver: Ownership taken.\n");
    429414                C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
    430415                async_usleep(50000);
    431                 return EOK;
     416                return;
    432417        }
    433418
     
    435420        /* Interrupt routing disabled && status != USB_RESET => BIOS active */
    436421        if (hc_status != C_HCFS_RESET) {
    437                 usb_log_debug("BIOS driver found.");
     422                usb_log_debug("BIOS driver found.\n");
    438423                if (hc_status == C_HCFS_OPERATIONAL) {
    439                         usb_log_info("BIOS driver: HC operational.");
    440                         return EOK;
     424                        usb_log_info("BIOS driver: HC operational.\n");
     425                        return;
    441426                }
    442427                /* HC is suspended assert resume for 20ms */
    443428                C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
    444429                async_usleep(20000);
    445                 usb_log_info("BIOS driver: HC resumed.");
    446                 return EOK;
     430                usb_log_info("BIOS driver: HC resumed.\n");
     431                return;
    447432        }
    448433
    449434        /* HC is in reset (hw startup) => no other driver
    450435         * maintain reset for at least the time specified in USB spec (50 ms)*/
    451         usb_log_debug("Host controller found in reset state.");
     436        usb_log_debug("Host controller found in reset state.\n");
    452437        async_usleep(50000);
    453         return EOK;
    454438}
    455439
     
    458442 * @param[in] instance OHCI hc driver structure.
    459443 */
    460 int 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 
     444void hc_start(hc_t *instance)
     445{
    465446        /* OHCI guide page 42 */
    466447        assert(instance);
    467         usb_log_debug2("Started hc initialization routine.");
     448        usb_log_debug2("Started hc initialization routine.\n");
    468449
    469450        /* Save contents of fm_interval register */
    470451        const uint32_t fm_interval = OHCI_RD(instance->registers->fm_interval);
    471         usb_log_debug2("Old value of HcFmInterval: %x.", fm_interval);
     452        usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);
    472453
    473454        /* Reset hc */
    474         usb_log_debug2("HC reset.");
     455        usb_log_debug2("HC reset.\n");
    475456        size_t time = 0;
    476457        OHCI_WR(instance->registers->command_status, CS_HCR);
     
    479460                time += 10;
    480461        }
    481         usb_log_debug2("HC reset complete in %zu us.", time);
     462        usb_log_debug2("HC reset complete in %zu us.\n", time);
    482463
    483464        /* Restore fm_interval */
     
    486467
    487468        /* hc is now in suspend state */
    488         usb_log_debug2("HC should be in suspend state(%x).",
     469        usb_log_debug2("HC should be in suspend state(%x).\n",
    489470            OHCI_RD(instance->registers->control));
    490471
     
    495476        OHCI_WR(instance->registers->bulk_head,
    496477            instance->lists[USB_TRANSFER_BULK].list_head_pa);
    497         usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").",
     478        usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").\n",
    498479            instance->lists[USB_TRANSFER_BULK].list_head,
    499480            instance->lists[USB_TRANSFER_BULK].list_head_pa);
     
    501482        OHCI_WR(instance->registers->control_head,
    502483            instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
    503         usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").",
     484        usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").\n",
    504485            instance->lists[USB_TRANSFER_CONTROL].list_head,
    505486            instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
     
    507488        /* Enable queues */
    508489        OHCI_SET(instance->registers->control, (C_PLE | C_IE | C_CLE | C_BLE));
    509         usb_log_debug("Queues enabled(%x).",
     490        usb_log_debug("Queues enabled(%x).\n",
    510491            OHCI_RD(instance->registers->control));
    511492
    512493        /* Enable interrupts */
    513         if (instance->base.irq_cap >= 0) {
     494        if (instance->hw_interrupts) {
    514495                OHCI_WR(instance->registers->interrupt_enable,
    515496                    OHCI_USED_INTERRUPTS);
    516                 usb_log_debug("Enabled interrupts: %x.",
     497                usb_log_debug("Enabled interrupts: %x.\n",
    517498                    OHCI_RD(instance->registers->interrupt_enable));
    518499                OHCI_WR(instance->registers->interrupt_enable, I_MI);
     
    524505        OHCI_WR(instance->registers->periodic_start,
    525506            ((frame_length / 10) * 9) & PS_MASK << PS_SHIFT);
    526         usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).",
     507        usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n",
    527508            OHCI_RD(instance->registers->periodic_start),
    528509            OHCI_RD(instance->registers->periodic_start), frame_length);
    529510        C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
    530         usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).",
     511        usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
    531512            OHCI_RD(instance->registers->control));
    532 
    533         return EOK;
    534 }
    535 
    536 /**
    537  * Setup roothub as a virtual hub.
    538  */
    539 int hc_setup_roothub(hc_device_t *hcd)
    540 {
    541         return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL);
    542513}
    543514
     
    555526        const errno_t ret = endpoint_list_init(&instance->lists[type], name); \
    556527        if (ret != EOK) { \
    557                 usb_log_error("Failed to setup %s endpoint list: %s.", \
     528                usb_log_error("Failed to setup %s endpoint list: %s.\n", \
    558529                    name, str_error(ret)); \
    559530                endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
     
    587558        memset(&instance->rh, 0, sizeof(instance->rh));
    588559        /* Init queues */
    589         errno_t ret = hc_init_transfer_lists(instance);
     560        const errno_t ret = hc_init_transfer_lists(instance);
    590561        if (ret != EOK) {
    591562                return ret;
     
    596567        if (instance->hcca == NULL)
    597568                return ENOMEM;
    598         usb_log_debug2("OHCI HCCA initialized at %p.", instance->hcca);
     569        usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
    599570
    600571        for (unsigned i = 0; i < HCCA_INT_EP_COUNT; ++i) {
     
    602573                    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    603574        }
    604         usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").",
     575        usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").\n",
    605576            instance->lists[USB_TRANSFER_INTERRUPT].list_head,
    606577            instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    607578
    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 
    616579        return EOK;
    617580}
Note: See TracChangeset for help on using the changeset viewer.