Changes in uspace/drv/ohci/hc.c [049eb87:8790650] in mainline


Ignore:
File:
1 edited

Legend:

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

    r049eb87 r8790650  
    4747static void hc_gain_control(hc_t *instance);
    4848static void hc_init_hw(hc_t *instance);
     49static int hc_init_transfer_lists(hc_t *instance);
     50static int hc_init_memory(hc_t *instance);
    4951/*----------------------------------------------------------------------------*/
    5052int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun)
     
    5961            &instance->manager, hub_address, hub_fun->handle);
    6062
     63        endpoint_t *ep = malloc(sizeof(endpoint_t));
     64        assert(ep);
     65        int ret = endpoint_init(ep, hub_address, 0, USB_DIRECTION_BOTH,
     66            USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64);
     67        assert(ret == EOK);
     68        ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, 0);
     69        assert(ret == EOK);
     70
    6171        char *match_str = NULL;
    62         int ret = asprintf(&match_str, "usb&class=hub");
    63         ret = (match_str == NULL) ? ret : EOK;
     72        ret = asprintf(&match_str, "usb&class=hub");
     73//      ret = (match_str == NULL) ? ret : EOK;
    6474        if (ret < 0) {
    65                 usb_log_error("Failed to create root hub match-id string.\n");
     75                usb_log_error(
     76                    "Failed(%d) to create root hub match-id string.\n", ret);
    6677                return ret;
    6778        }
     
    97108            ret, str_error(ret));
    98109
     110        hc_gain_control(instance);
     111        ret = hc_init_memory(instance);
     112        CHECK_RET_RETURN(ret, "Failed to create OHCI memory structures:%s.\n",
     113            ret, str_error(ret));
     114        hc_init_hw(instance);
     115
     116        rh_init(&instance->rh, dev, instance->registers);
     117
    99118        if (!interrupts) {
    100119                instance->interrupt_emulator =
     
    103122        }
    104123
    105         hc_gain_control(instance);
    106 
    107         rh_init(&instance->rh, dev, instance->registers);
    108 
    109         hc_init_hw(instance);
    110 
    111         /* TODO: implement */
    112124        return EOK;
    113125}
     
    117129        assert(instance);
    118130        assert(batch);
     131
     132        /* check for root hub communication */
    119133        if (batch->target.address == instance->rh.address) {
    120134                return rh_request(&instance->rh, batch);
    121135        }
    122         /* TODO: implement */
    123         return ENOTSUP;
     136
     137        transfer_list_add_batch(
     138            instance->transfers[batch->transfer_type], batch);
     139
     140        switch (batch->transfer_type) {
     141        case USB_TRANSFER_CONTROL:
     142                instance->registers->control &= ~C_CLE;
     143                instance->registers->command_status |= CS_CLF;
     144                usb_log_debug2("Set control transfer filled: %x.\n",
     145                        instance->registers->command_status);
     146                instance->registers->control |= C_CLE;
     147                break;
     148        case USB_TRANSFER_BULK:
     149                instance->registers->command_status |= CS_BLF;
     150                usb_log_debug2("Set bulk transfer filled: %x.\n",
     151                        instance->registers->command_status);
     152                break;
     153        default:
     154                break;
     155        }
     156        return EOK;
    124157}
    125158/*----------------------------------------------------------------------------*/
     
    127160{
    128161        assert(instance);
    129         if (status == 0)
     162        if ((status & ~IS_SF) == 0) /* ignore sof status */
    130163                return;
    131164        if (status & IS_RHSC)
     
    134167        usb_log_info("OHCI interrupt: %x.\n", status);
    135168
    136         /* TODO: Check for further interrupt causes */
    137         /* TODO: implement */
     169
     170        LIST_INITIALIZE(done);
     171        transfer_list_remove_finished(&instance->transfers_interrupt, &done);
     172        transfer_list_remove_finished(&instance->transfers_isochronous, &done);
     173        transfer_list_remove_finished(&instance->transfers_control, &done);
     174        transfer_list_remove_finished(&instance->transfers_bulk, &done);
     175
     176        while (!list_empty(&done)) {
     177                link_t *item = done.next;
     178                list_remove(item);
     179                usb_transfer_batch_t *batch =
     180                    list_get_instance(item, usb_transfer_batch_t, link);
     181                usb_transfer_batch_finish(batch);
     182        }
    138183}
    139184/*----------------------------------------------------------------------------*/
     
    154199{
    155200        assert(instance);
     201        /* Turn off legacy emulation */
     202        volatile uint32_t *ohci_emulation_reg =
     203            (uint32_t*)((char*)instance->registers + 0x100);
     204        usb_log_debug("OHCI legacy register %p: %x.\n",
     205                ohci_emulation_reg, *ohci_emulation_reg);
     206        *ohci_emulation_reg = 0;
     207
    156208        /* Interrupt routing enabled => smm driver is active */
    157209        if (instance->registers->control & C_IR) {
    158                 usb_log_info("Found SMM driver requesting ownership change.\n");
     210                usb_log_debug("SMM driver: request ownership change.\n");
    159211                instance->registers->command_status |= CS_OCR;
    160212                while (instance->registers->control & C_IR) {
    161213                        async_usleep(1000);
    162214                }
    163                 usb_log_info("Ownership taken from SMM driver.\n");
     215                usb_log_info("SMM driver: Ownership taken.\n");
    164216                return;
    165217        }
     
    169221        /* Interrupt routing disabled && status != USB_RESET => BIOS active */
    170222        if (hc_status != C_HCFS_RESET) {
    171                 usb_log_info("Found BIOS driver.\n");
     223                usb_log_debug("BIOS driver found.\n");
    172224                if (hc_status == C_HCFS_OPERATIONAL) {
    173                         usb_log_info("HC operational(BIOS).\n");
     225                        usb_log_info("BIOS driver: HC operational.\n");
    174226                        return;
    175227                }
     
    177229                instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);
    178230                async_usleep(20000);
     231                usb_log_info("BIOS driver: HC resumed.\n");
    179232                return;
    180233        }
     
    182235        /* HC is in reset (hw startup) => no other driver
    183236         * maintain reset for at least the time specified in USB spec (50 ms)*/
     237        usb_log_info("HC found in reset.\n");
    184238        async_usleep(50000);
    185 
    186         /* turn off legacy emulation */
    187         volatile uint32_t *ohci_emulation_reg =
    188             (uint32_t*)((char*)instance->registers + 0x100);
    189         usb_log_info("OHCI legacy register status %p: %x.\n",
    190                 ohci_emulation_reg, *ohci_emulation_reg);
    191         *ohci_emulation_reg = 0;
    192 
    193239}
    194240/*----------------------------------------------------------------------------*/
    195241void hc_init_hw(hc_t *instance)
    196242{
    197         assert(instance);
     243        /* OHCI guide page 42 */
     244        assert(instance);
     245        usb_log_debug2("Started hc initialization routine.\n");
     246
     247        /* Save contents of fm_interval register */
    198248        const uint32_t fm_interval = instance->registers->fm_interval;
     249        usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);
     250
     251        /* Reset hc */
     252        usb_log_debug2("HC reset.\n");
     253        size_t time = 0;
    199254        instance->registers->command_status = CS_HCR;
    200         async_usleep(10);
     255        while (instance->registers->command_status & CS_HCR) {
     256                async_usleep(10);
     257                time += 10;
     258        }
     259        usb_log_debug2("HC reset complete in %zu us.\n", time);
     260
     261        /* Restore fm_interval */
    201262        instance->registers->fm_interval = fm_interval;
    202263        assert((instance->registers->command_status & CS_HCR) == 0);
     264
    203265        /* hc is now in suspend state */
    204         /* TODO: init HCCA block */
    205         /* TODO: init queues */
    206         /* TODO: enable queues */
    207         /* TODO: enable interrupts */
    208         /* TODO: set periodic start to 90% */
     266        usb_log_debug2("HC should be in suspend state(%x).\n",
     267            instance->registers->control);
     268
     269        /* Enable queues */
     270        instance->registers->control |= (C_PLE | C_IE | C_CLE | C_BLE);
     271        usb_log_debug2("All queues enabled(%x).\n",
     272            instance->registers->control);
     273
     274        /* Disable interrupts */
     275        instance->registers->interrupt_disable = I_SF | I_OC;
     276        usb_log_debug2("Disabling interrupts: %x.\n",
     277            instance->registers->interrupt_disable);
     278        instance->registers->interrupt_disable = I_MI;
     279        usb_log_debug2("Enabled interrupts: %x.\n",
     280            instance->registers->interrupt_enable);
     281
     282        /* Set periodic start to 90% */
     283        uint32_t frame_length = ((fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK);
     284        instance->registers->periodic_start = (frame_length / 10) * 9;
     285        usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n",
     286            instance->registers->periodic_start,
     287            instance->registers->periodic_start, frame_length);
    209288
    210289        instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
    211         usb_log_info("OHCI HC up and running.\n");
     290        usb_log_info("OHCI HC up and running(%x).\n",
     291            instance->registers->control);
     292}
     293/*----------------------------------------------------------------------------*/
     294int hc_init_transfer_lists(hc_t *instance)
     295{
     296        assert(instance);
     297
     298#define SETUP_TRANSFER_LIST(type, name) \
     299do { \
     300        int ret = transfer_list_init(&instance->type, name); \
     301        if (ret != EOK) { \
     302                usb_log_error("Failed(%d) to setup %s transfer list.\n", \
     303                    ret, name); \
     304                transfer_list_fini(&instance->transfers_isochronous); \
     305                transfer_list_fini(&instance->transfers_interrupt); \
     306                transfer_list_fini(&instance->transfers_control); \
     307                transfer_list_fini(&instance->transfers_bulk); \
     308        } \
     309} while (0)
     310
     311        SETUP_TRANSFER_LIST(transfers_isochronous, "ISOCHRONOUS");
     312        SETUP_TRANSFER_LIST(transfers_interrupt, "INTERRUPT");
     313        SETUP_TRANSFER_LIST(transfers_control, "CONTROL");
     314        SETUP_TRANSFER_LIST(transfers_bulk, "BULK");
     315
     316        transfer_list_set_next(&instance->transfers_interrupt,
     317            &instance->transfers_isochronous);
     318
     319        /* Assign pointers to be used during scheduling */
     320        instance->transfers[USB_TRANSFER_INTERRUPT] =
     321          &instance->transfers_interrupt;
     322        instance->transfers[USB_TRANSFER_ISOCHRONOUS] =
     323          &instance->transfers_interrupt;
     324        instance->transfers[USB_TRANSFER_CONTROL] =
     325          &instance->transfers_control;
     326        instance->transfers[USB_TRANSFER_BULK] =
     327          &instance->transfers_bulk;
     328
     329        return EOK;
     330#undef CHECK_RET_CLEAR_RETURN
     331}
     332/*----------------------------------------------------------------------------*/
     333int hc_init_memory(hc_t *instance)
     334{
     335        assert(instance);
     336        /* Init queues */
     337        hc_init_transfer_lists(instance);
     338
     339        /*Init HCCA */
     340        instance->hcca = malloc32(sizeof(hcca_t));
     341        if (instance->hcca == NULL)
     342                return ENOMEM;
     343        bzero(instance->hcca, sizeof(hcca_t));
     344        instance->registers->hcca = addr_to_phys(instance->hcca);
     345        usb_log_debug2("OHCI HCCA initialized at %p(%p).\n",
     346            instance->hcca, instance->registers->hcca);
     347
     348        /* Use queues */
     349        instance->registers->bulk_head = instance->transfers_bulk.list_head_pa;
     350        usb_log_debug2("Bulk HEAD set to: %p(%p).\n",
     351            instance->transfers_bulk.list_head,
     352            instance->transfers_bulk.list_head_pa);
     353
     354        instance->registers->control_head =
     355            instance->transfers_control.list_head_pa;
     356        usb_log_debug2("Control HEAD set to: %p(%p).\n",
     357            instance->transfers_control.list_head,
     358            instance->transfers_control.list_head_pa);
     359
     360        unsigned i = 0;
     361        for (; i < 32; ++i) {
     362                instance->hcca->int_ep[i] =
     363                    instance->transfers_interrupt.list_head_pa;
     364        }
     365        usb_log_debug2("Interrupt HEADs set to: %p(%p).\n",
     366            instance->transfers_interrupt.list_head,
     367            instance->transfers_interrupt.list_head_pa);
     368
     369        return EOK;
    212370}
    213371/**
Note: See TracChangeset for help on using the changeset viewer.