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


Ignore:
File:
1 edited

Legend:

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

    rd6522dd r049eb87  
    4343
    4444#include "hc.h"
    45 #include "hcd_endpoint.h"
    4645
    4746static int interrupt_emulator(hc_t *instance);
    4847static void hc_gain_control(hc_t *instance);
    4948static void hc_init_hw(hc_t *instance);
    50 static int hc_init_transfer_lists(hc_t *instance);
    51 static int hc_init_memory(hc_t *instance);
    5249/*----------------------------------------------------------------------------*/
    5350int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun)
     
    5552        assert(instance);
    5653        assert(hub_fun);
    57 
    58         int ret;
    5954
    6055        usb_address_t hub_address =
    6156            device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL);
    62         if (hub_address <= 0) {
    63                 usb_log_error("Failed to get OHCI root hub address.\n");
    64                 return hub_address;
    65         }
    6657        instance->rh.address = hub_address;
    6758        usb_device_keeper_bind(
    6859            &instance->manager, hub_address, hub_fun->handle);
    6960
    70         ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL,
    71             USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0);
    72         if (ret != EOK) {
    73                 usb_log_error("Failed to add OHCI rh endpoint 0.\n");
    74                 usb_device_keeper_release(&instance->manager, hub_address);
    75                 return ret;
    76         }
    77 
    7861        char *match_str = NULL;
    79         /* DDF needs heap allocated string */
    80         ret = asprintf(&match_str, "usb&class=hub");
     62        int ret = asprintf(&match_str, "usb&class=hub");
     63        ret = (match_str == NULL) ? ret : EOK;
    8164        if (ret < 0) {
    82                 usb_log_error(
    83                     "Failed(%d) to create root hub match-id string.\n", ret);
    84                 usb_device_keeper_release(&instance->manager, hub_address);
     65                usb_log_error("Failed to create root hub match-id string.\n");
    8566                return ret;
    8667        }
     
    8869        ret = ddf_fun_add_match_id(hub_fun, match_str, 100);
    8970        if (ret != EOK) {
    90                 usb_log_error("Failed add root hub match-id.\n");
     71                usb_log_error("Failed add create root hub match-id.\n");
    9172        }
    9273        return ret;
     
    10990            ret, str_error(ret));
    11091
     92        instance->ddf_instance = fun;
    11193        usb_device_keeper_init(&instance->manager);
    11294        ret = usb_endpoint_manager_init(&instance->ep_manager,
     
    11597            ret, str_error(ret));
    11698
    117         hc_gain_control(instance);
    118         ret = hc_init_memory(instance);
    119         CHECK_RET_RETURN(ret, "Failed to create OHCI memory structures:%s.\n",
    120             ret, str_error(ret));
    121         hc_init_hw(instance);
    122         fibril_mutex_initialize(&instance->guard);
    123 
    124         rh_init(&instance->rh, instance->registers);
    125 
    12699        if (!interrupts) {
    127100                instance->interrupt_emulator =
     
    130103        }
    131104
    132         list_initialize(&instance->pending_batches);
    133 #undef CHECK_RET_RETURN
     105        hc_gain_control(instance);
     106
     107        rh_init(&instance->rh, dev, instance->registers);
     108
     109        hc_init_hw(instance);
     110
     111        /* TODO: implement */
    134112        return EOK;
    135113}
    136114/*----------------------------------------------------------------------------*/
    137 int hc_add_endpoint(
    138     hc_t *instance, usb_address_t address, usb_endpoint_t endpoint,
    139     usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction,
    140     size_t mps, size_t size, unsigned interval)
    141 {
    142         endpoint_t *ep = malloc(sizeof(endpoint_t));
    143         if (ep == NULL)
    144                 return ENOMEM;
    145         int ret =
    146             endpoint_init(ep, address, endpoint, direction, type, speed, mps);
    147         if (ret != EOK) {
    148                 free(ep);
    149                 return ret;
    150         }
    151 
    152         hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);
    153         if (hcd_ep == NULL) {
    154                 endpoint_destroy(ep);
    155                 return ENOMEM;
    156         }
    157 
    158         ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
    159         if (ret != EOK) {
    160                 hcd_endpoint_clear(ep);
    161                 endpoint_destroy(ep);
    162                 return ret;
    163         }
    164 
    165         /* Enqueue hcd_ep */
    166         switch (ep->transfer_type) {
    167         case USB_TRANSFER_CONTROL:
    168                 instance->registers->control &= ~C_CLE;
    169                 endpoint_list_add_ep(
    170                     &instance->lists[ep->transfer_type], hcd_ep);
    171                 instance->registers->control_current = 0;
    172                 instance->registers->control |= C_CLE;
    173                 break;
    174         case USB_TRANSFER_BULK:
    175                 instance->registers->control &= ~C_BLE;
    176                 endpoint_list_add_ep(
    177                     &instance->lists[ep->transfer_type], hcd_ep);
    178                 instance->registers->control |= C_BLE;
    179                 break;
    180         case USB_TRANSFER_ISOCHRONOUS:
    181         case USB_TRANSFER_INTERRUPT:
    182                 instance->registers->control &= (~C_PLE & ~C_IE);
    183                 endpoint_list_add_ep(
    184                     &instance->lists[ep->transfer_type], hcd_ep);
    185                 instance->registers->control |= C_PLE | C_IE;
    186                 break;
    187         default:
    188                 break;
    189         }
    190 
    191         return EOK;
    192 }
    193 /*----------------------------------------------------------------------------*/
    194 int hc_remove_endpoint(hc_t *instance, usb_address_t address,
    195     usb_endpoint_t endpoint, usb_direction_t direction)
    196 {
    197         assert(instance);
    198         fibril_mutex_lock(&instance->guard);
    199         endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
    200             address, endpoint, direction, NULL);
    201         if (ep == NULL) {
    202                 usb_log_error("Endpoint unregister failed: No such EP.\n");
    203                 fibril_mutex_unlock(&instance->guard);
    204                 return ENOENT;
    205         }
    206 
    207         hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep);
    208         if (hcd_ep) {
    209                 /* Dequeue hcd_ep */
    210                 switch (ep->transfer_type) {
    211                 case USB_TRANSFER_CONTROL:
    212                         instance->registers->control &= ~C_CLE;
    213                         endpoint_list_remove_ep(
    214                             &instance->lists[ep->transfer_type], hcd_ep);
    215                         instance->registers->control_current = 0;
    216                         instance->registers->control |= C_CLE;
    217                         break;
    218                 case USB_TRANSFER_BULK:
    219                         instance->registers->control &= ~C_BLE;
    220                         endpoint_list_remove_ep(
    221                             &instance->lists[ep->transfer_type], hcd_ep);
    222                         instance->registers->control |= C_BLE;
    223                         break;
    224                 case USB_TRANSFER_ISOCHRONOUS:
    225                 case USB_TRANSFER_INTERRUPT:
    226                         instance->registers->control &= (~C_PLE & ~C_IE);
    227                         endpoint_list_remove_ep(
    228                             &instance->lists[ep->transfer_type], hcd_ep);
    229                         instance->registers->control |= C_PLE | C_IE;
    230                         break;
    231                 default:
    232                         break;
    233                 }
    234                 hcd_endpoint_clear(ep);
    235         } else {
    236                 usb_log_warning("Endpoint without hcd equivalent structure.\n");
    237         }
    238         int ret = usb_endpoint_manager_unregister_ep(&instance->ep_manager,
    239             address, endpoint, direction);
    240         fibril_mutex_unlock(&instance->guard);
    241         return ret;
    242 }
    243 /*----------------------------------------------------------------------------*/
    244 endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address,
    245     usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw)
    246 {
    247         assert(instance);
    248         fibril_mutex_lock(&instance->guard);
    249         endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
    250             address, endpoint, direction, bw);
    251         fibril_mutex_unlock(&instance->guard);
    252         return ep;
    253 }
    254 /*----------------------------------------------------------------------------*/
    255115int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
    256116{
    257117        assert(instance);
    258118        assert(batch);
    259         assert(batch->ep);
    260 
    261         /* check for root hub communication */
    262         if (batch->ep->address == instance->rh.address) {
     119        if (batch->target.address == instance->rh.address) {
    263120                return rh_request(&instance->rh, batch);
    264121        }
    265 
    266         fibril_mutex_lock(&instance->guard);
    267         list_append(&batch->link, &instance->pending_batches);
    268         batch_commit(batch);
    269         switch (batch->ep->transfer_type) {
    270         case USB_TRANSFER_CONTROL:
    271                 instance->registers->command_status |= CS_CLF;
    272                 break;
    273         case USB_TRANSFER_BULK:
    274                 instance->registers->command_status |= CS_BLF;
    275                 break;
    276         default:
    277                 break;
    278         }
    279 
    280         fibril_mutex_unlock(&instance->guard);
    281         return EOK;
     122        /* TODO: implement */
     123        return ENOTSUP;
    282124}
    283125/*----------------------------------------------------------------------------*/
     
    285127{
    286128        assert(instance);
    287         if ((status & ~IS_SF) == 0) /* ignore sof status */
     129        if (status == 0)
    288130                return;
    289131        if (status & IS_RHSC)
    290132                rh_interrupt(&instance->rh);
    291133
    292         usb_log_debug("OHCI interrupt: %x.\n", status);
    293 
    294         if (status & IS_WDH) {
    295                 fibril_mutex_lock(&instance->guard);
    296                 usb_log_debug2("HCCA: %p-%p(%p).\n", instance->hcca,
    297                     instance->registers->hcca, addr_to_phys(instance->hcca));
    298                 usb_log_debug2("Periodic current: %p.\n",
    299                     instance->registers->periodic_current);
    300 
    301                 link_t *current = instance->pending_batches.next;
    302                 while (current != &instance->pending_batches) {
    303                         link_t *next = current->next;
    304                         usb_transfer_batch_t *batch =
    305                             usb_transfer_batch_from_link(current);
    306 
    307                         if (batch_is_complete(batch)) {
    308                                 list_remove(current);
    309                                 usb_transfer_batch_finish(batch);
    310                         }
    311                         current = next;
    312                 }
    313                 fibril_mutex_unlock(&instance->guard);
    314         }
     134        usb_log_info("OHCI interrupt: %x.\n", status);
     135
     136        /* TODO: Check for further interrupt causes */
     137        /* TODO: implement */
    315138}
    316139/*----------------------------------------------------------------------------*/
     
    323146                instance->registers->interrupt_status = status;
    324147                hc_interrupt(instance, status);
    325                 async_usleep(50000);
     148                async_usleep(1000);
    326149        }
    327150        return EOK;
     
    331154{
    332155        assert(instance);
    333         /* Turn off legacy emulation */
    334         volatile uint32_t *ohci_emulation_reg =
    335             (uint32_t*)((char*)instance->registers + 0x100);
    336         usb_log_debug("OHCI legacy register %p: %x.\n",
    337                 ohci_emulation_reg, *ohci_emulation_reg);
    338         *ohci_emulation_reg = 0;
    339 
    340156        /* Interrupt routing enabled => smm driver is active */
    341157        if (instance->registers->control & C_IR) {
    342                 usb_log_debug("SMM driver: request ownership change.\n");
     158                usb_log_info("Found SMM driver requesting ownership change.\n");
    343159                instance->registers->command_status |= CS_OCR;
    344160                while (instance->registers->control & C_IR) {
    345161                        async_usleep(1000);
    346162                }
    347                 usb_log_info("SMM driver: Ownership taken.\n");
     163                usb_log_info("Ownership taken from SMM driver.\n");
    348164                return;
    349165        }
     
    353169        /* Interrupt routing disabled && status != USB_RESET => BIOS active */
    354170        if (hc_status != C_HCFS_RESET) {
    355                 usb_log_debug("BIOS driver found.\n");
     171                usb_log_info("Found BIOS driver.\n");
    356172                if (hc_status == C_HCFS_OPERATIONAL) {
    357                         usb_log_info("BIOS driver: HC operational.\n");
     173                        usb_log_info("HC operational(BIOS).\n");
    358174                        return;
    359175                }
     
    361177                instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);
    362178                async_usleep(20000);
    363                 usb_log_info("BIOS driver: HC resumed.\n");
    364179                return;
    365180        }
     
    367182        /* HC is in reset (hw startup) => no other driver
    368183         * maintain reset for at least the time specified in USB spec (50 ms)*/
    369         usb_log_info("HC found in reset.\n");
    370184        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
    371193}
    372194/*----------------------------------------------------------------------------*/
    373195void hc_init_hw(hc_t *instance)
    374196{
    375         /* OHCI guide page 42 */
    376         assert(instance);
    377         usb_log_debug2("Started hc initialization routine.\n");
    378 
    379         /* Save contents of fm_interval register */
     197        assert(instance);
    380198        const uint32_t fm_interval = instance->registers->fm_interval;
    381         usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);
    382 
    383         /* Reset hc */
    384         usb_log_debug2("HC reset.\n");
    385         size_t time = 0;
    386199        instance->registers->command_status = CS_HCR;
    387         while (instance->registers->command_status & CS_HCR) {
    388                 async_usleep(10);
    389                 time += 10;
    390         }
    391         usb_log_debug2("HC reset complete in %zu us.\n", time);
    392 
    393         /* Restore fm_interval */
     200        async_usleep(10);
    394201        instance->registers->fm_interval = fm_interval;
    395202        assert((instance->registers->command_status & CS_HCR) == 0);
    396 
    397203        /* hc is now in suspend state */
    398         usb_log_debug2("HC should be in suspend state(%x).\n",
    399             instance->registers->control);
    400 
    401         /* Use HCCA */
    402         instance->registers->hcca = addr_to_phys(instance->hcca);
    403 
    404         /* Use queues */
    405         instance->registers->bulk_head =
    406             instance->lists[USB_TRANSFER_BULK].list_head_pa;
    407         usb_log_debug2("Bulk HEAD set to: %p(%p).\n",
    408             instance->lists[USB_TRANSFER_BULK].list_head,
    409             instance->lists[USB_TRANSFER_BULK].list_head_pa);
    410 
    411         instance->registers->control_head =
    412             instance->lists[USB_TRANSFER_CONTROL].list_head_pa;
    413         usb_log_debug2("Control HEAD set to: %p(%p).\n",
    414             instance->lists[USB_TRANSFER_CONTROL].list_head,
    415             instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
    416 
    417         /* Enable queues */
    418         instance->registers->control |= (C_PLE | C_IE | C_CLE | C_BLE);
    419         usb_log_debug2("All queues enabled(%x).\n",
    420             instance->registers->control);
    421 
    422         /* Disable interrupts */
    423         instance->registers->interrupt_disable = I_SF | I_OC;
    424         usb_log_debug2("Disabling interrupts: %x.\n",
    425             instance->registers->interrupt_disable);
    426         instance->registers->interrupt_disable = I_MI;
    427         usb_log_debug2("Enabled interrupts: %x.\n",
    428             instance->registers->interrupt_enable);
    429 
    430         /* Set periodic start to 90% */
    431         uint32_t frame_length = ((fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK);
    432         instance->registers->periodic_start = (frame_length / 10) * 9;
    433         usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n",
    434             instance->registers->periodic_start,
    435             instance->registers->periodic_start, frame_length);
     204        /* TODO: init HCCA block */
     205        /* TODO: init queues */
     206        /* TODO: enable queues */
     207        /* TODO: enable interrupts */
     208        /* TODO: set periodic start to 90% */
    436209
    437210        instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
    438         usb_log_info("OHCI HC up and running(%x).\n",
    439             instance->registers->control);
    440 }
    441 /*----------------------------------------------------------------------------*/
    442 int hc_init_transfer_lists(hc_t *instance)
    443 {
    444         assert(instance);
    445 
    446 #define SETUP_ENDPOINT_LIST(type) \
    447 do { \
    448         const char *name = usb_str_transfer_type(type); \
    449         int ret = endpoint_list_init(&instance->lists[type], name); \
    450         if (ret != EOK) { \
    451                 usb_log_error("Failed(%d) to setup %s endpoint list.\n", \
    452                     ret, name); \
    453                 endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]); \
    454                 endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \
    455                 endpoint_list_fini(&instance->lists[USB_TRANSFER_CONTROL]); \
    456                 endpoint_list_fini(&instance->lists[USB_TRANSFER_BULK]); \
    457         } \
    458 } while (0)
    459 
    460         SETUP_ENDPOINT_LIST(USB_TRANSFER_ISOCHRONOUS);
    461         SETUP_ENDPOINT_LIST(USB_TRANSFER_INTERRUPT);
    462         SETUP_ENDPOINT_LIST(USB_TRANSFER_CONTROL);
    463         SETUP_ENDPOINT_LIST(USB_TRANSFER_BULK);
    464 #undef SETUP_ENDPOINT_LIST
    465         endpoint_list_set_next(&instance->lists[USB_TRANSFER_INTERRUPT],
    466             &instance->lists[USB_TRANSFER_ISOCHRONOUS]);
    467 
    468         return EOK;
    469 }
    470 /*----------------------------------------------------------------------------*/
    471 int hc_init_memory(hc_t *instance)
    472 {
    473         assert(instance);
    474         /* Init queues */
    475         hc_init_transfer_lists(instance);
    476 
    477         /*Init HCCA */
    478         instance->hcca = malloc32(sizeof(hcca_t));
    479         if (instance->hcca == NULL)
    480                 return ENOMEM;
    481         bzero(instance->hcca, sizeof(hcca_t));
    482         usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
    483 
    484         unsigned i = 0;
    485         for (; i < 32; ++i) {
    486                 instance->hcca->int_ep[i] =
    487                     instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa;
    488         }
    489         usb_log_debug2("Interrupt HEADs set to: %p(%p).\n",
    490             instance->lists[USB_TRANSFER_INTERRUPT].list_head,
    491             instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    492 
    493         return EOK;
     211        usb_log_info("OHCI HC up and running.\n");
    494212}
    495213/**
Note: See TracChangeset for help on using the changeset viewer.