Ignore:
File:
1 edited

Legend:

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

    rf83666c rd57122c  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 
    2928/** @addtogroup drvusbohcihc
    3029 * @{
     
    3332 * @brief OHCI Host controller driver routines
    3433 */
    35 
    3634#include <errno.h>
    37 #include <stdbool.h>
    3835#include <str_error.h>
    3936#include <adt/list.h>
     
    5249static const irq_pio_range_t ohci_pio_ranges[] = {
    5350        {
    54                 .base = 0,
     51                .base = 0,      /* filled later */
    5552                .size = sizeof(ohci_regs_t)
    5653        }
     
    5855
    5956static const irq_cmd_t ohci_irq_commands[] = {
    60         {
    61                 .cmd = CMD_PIO_READ_32,
    62                 .dstarg = 1,
    63                 .addr = NULL
    64         },
    65         {
    66                 .cmd = CMD_AND,
    67                 .srcarg = 1,
    68                 .dstarg = 2,
    69                 .value = 0
    70         },
    71         {
    72                 .cmd = CMD_PREDICATE,
    73                 .srcarg = 2,
    74                 .value = 2
    75         },
    76         {
    77                 .cmd = CMD_PIO_WRITE_A_32,
    78                 .srcarg = 1,
    79                 .addr = NULL
    80         },
    81         {
    82                 .cmd = CMD_ACCEPT
    83         }
    84 };
    85 
    86 enum {
    87         /** Number of PIO ranges used in IRQ code */
    88         hc_irq_pio_range_count =
    89             sizeof(ohci_pio_ranges) / sizeof(irq_pio_range_t),
    90 
    91         /** Number of commands used in IRQ code */
    92         hc_irq_cmd_count =
    93             sizeof(ohci_irq_commands) / sizeof(irq_cmd_t)
     57        { .cmd = CMD_PIO_READ_32, .dstarg = 1, .addr = NULL /* filled later */ },
     58        { .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2, .value = OHCI_USED_INTERRUPTS },
     59        { .cmd = CMD_PREDICATE, .srcarg = 2, .value = 2 },
     60        { .cmd = CMD_PIO_WRITE_A_32, .srcarg = 1, .addr = NULL /* filled later */ },
     61        { .cmd = CMD_ACCEPT },
    9462};
    9563
     
    10068static int interrupt_emulator(hc_t *instance);
    10169static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
    102 
     70/*----------------------------------------------------------------------------*/
     71/** Get number of PIO ranges used in IRQ code.
     72 * @return Number of ranges.
     73 */
     74size_t hc_irq_pio_range_count(void)
     75{
     76        return sizeof(ohci_pio_ranges) / sizeof(irq_pio_range_t);
     77}
     78/*----------------------------------------------------------------------------*/
     79/*----------------------------------------------------------------------------*/
     80/** Get number of commands used in IRQ code.
     81 * @return Number of commands.
     82 */
     83size_t hc_irq_cmd_count(void)
     84{
     85        return sizeof(ohci_irq_commands) / sizeof(irq_cmd_t);
     86}
     87/*----------------------------------------------------------------------------*/
    10388/** Generate IRQ code.
    10489 * @param[out] ranges PIO ranges buffer.
     
    127112        cmds[0].addr = (void *) &registers->interrupt_status;
    128113        cmds[3].addr = (void *) &registers->interrupt_status;
    129         OHCI_WR(cmds[1].value, OHCI_USED_INTERRUPTS);
    130114
    131115        return EOK;
    132116}
    133 
    134 /** Register interrupt handler.
    135  *
    136  * @param[in] device Host controller DDF device
    137  * @param[in] reg_base Register range base
    138  * @param[in] reg_size Register range size
    139  * @param[in] irq Interrupt number
    140  * @paran[in] handler Interrupt handler
    141  *
    142  * @return EOK on success or negative error code
    143  */
    144 int hc_register_irq_handler(ddf_dev_t *device, uintptr_t reg_base, size_t reg_size,
    145     int irq, interrupt_handler_t handler)
    146 {
    147         int rc;
    148 
    149         irq_pio_range_t irq_ranges[hc_irq_pio_range_count];
    150         irq_cmd_t irq_cmds[hc_irq_cmd_count];
    151 
    152         irq_code_t irq_code = {
    153                 .rangecount = hc_irq_pio_range_count,
    154                 .ranges = irq_ranges,
    155                 .cmdcount = hc_irq_cmd_count,
    156                 .cmds = irq_cmds
    157         };
    158 
    159         rc = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds,
    160             sizeof(irq_cmds), reg_base, reg_size);
    161         if (rc != EOK) {
    162                 usb_log_error("Failed to generate IRQ code: %s.\n",
    163                     str_error(rc));
    164                 return rc;
    165         }
    166 
    167         /* Register handler to avoid interrupt lockup */
    168         rc = register_interrupt_handler(device, irq, handler, &irq_code);
    169         if (rc != EOK) {
    170                 usb_log_error("Failed to register interrupt handler: %s.\n",
    171                     str_error(rc));
    172                 return rc;
    173         }
    174 
    175         return EOK;
    176 }
    177 
     117/*----------------------------------------------------------------------------*/
    178118/** Announce OHCI root hub to the DDF
    179119 *
     
    184124int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun)
    185125{
    186         bool addr_reqd = false;
    187         bool ep_added = false;
    188         bool fun_bound = false;
    189         int rc;
    190 
    191126        assert(instance);
    192127        assert(hub_fun);
     
    194129        /* Try to get address 1 for root hub. */
    195130        instance->rh.address = 1;
    196         rc = usb_device_manager_request_address(
     131        int ret = usb_device_manager_request_address(
    197132            &instance->generic.dev_manager, &instance->rh.address, false,
    198133            USB_SPEED_FULL);
    199         if (rc != EOK) {
     134        if (ret != EOK) {
    200135                usb_log_error("Failed to get OHCI root hub address: %s\n",
    201                     str_error(rc));
    202                 goto error;
    203         }
    204 
    205         addr_reqd = true;
    206 
    207         rc = usb_endpoint_manager_add_ep(
     136                    str_error(ret));
     137                return ret;
     138        }
     139
     140#define CHECK_RET_UNREG_RETURN(ret, message...) \
     141if (ret != EOK) { \
     142        usb_log_error(message); \
     143        usb_endpoint_manager_remove_ep( \
     144            &instance->generic.ep_manager, instance->rh.address, 0, \
     145            USB_DIRECTION_BOTH, NULL, NULL); \
     146        usb_device_manager_release_address( \
     147            &instance->generic.dev_manager, instance->rh.address); \
     148        return ret; \
     149} else (void)0
     150
     151        ret = usb_endpoint_manager_add_ep(
    208152            &instance->generic.ep_manager, instance->rh.address, 0,
    209153            USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64,
    210154            0, NULL, NULL);
    211         if (rc != EOK) {
    212                 usb_log_error("Failed to register root hub control endpoint: %s.\n",
    213                     str_error(rc));
    214                 goto error;
    215         }
    216 
    217         ep_added = true;
    218 
    219         rc = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100);
    220         if (rc != EOK) {
    221                 usb_log_error("Failed to add root hub match-id: %s.\n",
    222                     str_error(rc));
    223                 goto error;
    224         }
    225 
    226         rc = ddf_fun_bind(hub_fun);
    227         if (rc != EOK) {
    228                 usb_log_error("Failed to bind root hub function: %s.\n",
    229                     str_error(rc));
    230                 goto error;
    231         }
    232 
    233         fun_bound = true;
    234 
    235         rc = usb_device_manager_bind_address(&instance->generic.dev_manager,
    236             instance->rh.address, ddf_fun_get_handle(hub_fun));
    237         if (rc != EOK) {
     155        CHECK_RET_UNREG_RETURN(ret,
     156            "Failed to register root hub control endpoint: %s.\n",
     157            str_error(ret));
     158
     159        ret = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100);
     160        CHECK_RET_UNREG_RETURN(ret,
     161            "Failed to add root hub match-id: %s.\n", str_error(ret));
     162
     163        ret = ddf_fun_bind(hub_fun);
     164        CHECK_RET_UNREG_RETURN(ret,
     165            "Failed to bind root hub function: %s.\n", str_error(ret));
     166
     167        ret = usb_device_manager_bind_address(&instance->generic.dev_manager,
     168            instance->rh.address, hub_fun->handle);
     169        if (ret != EOK)
    238170                usb_log_warning("Failed to bind root hub address: %s.\n",
    239                     str_error(rc));
    240         }
     171                    str_error(ret));
    241172
    242173        return EOK;
    243 error:
    244         if (fun_bound)
    245                 ddf_fun_unbind(hub_fun);
    246         if (ep_added) {
    247                 usb_endpoint_manager_remove_ep(
    248                     &instance->generic.ep_manager, instance->rh.address, 0,
    249                     USB_DIRECTION_BOTH, NULL, NULL);
    250         }
    251         if (addr_reqd) {
    252                 usb_device_manager_release_address(
    253                     &instance->generic.dev_manager, instance->rh.address);
    254         }
    255         return rc;
    256 }
    257 
     174#undef CHECK_RET_RELEASE
     175}
     176/*----------------------------------------------------------------------------*/
    258177/** Initialize OHCI hc driver structure
    259178 *
     
    268187        assert(instance);
    269188
    270         int rc =
     189#define CHECK_RET_RETURN(ret, message...) \
     190if (ret != EOK) { \
     191        usb_log_error(message); \
     192        return ret; \
     193} else (void)0
     194
     195        int ret =
    271196            pio_enable((void*)regs, reg_size, (void**)&instance->registers);
    272         if (rc != EOK) {
    273                 usb_log_error("Failed to gain access to device registers: %s.\n",
    274                     str_error(rc));
    275                 return rc;
    276         }
     197        CHECK_RET_RETURN(ret,
     198            "Failed to gain access to device registers: %s.\n", str_error(ret));
    277199
    278200        list_initialize(&instance->pending_batches);
     
    285207        instance->generic.ep_remove_hook = ohci_endpoint_fini;
    286208
    287         rc = hc_init_memory(instance);
    288         if (rc != EOK) {
    289                 usb_log_error("Failed to create OHCI memory structures: %s.\n",
    290                     str_error(rc));
    291                 return rc;
    292         }
     209        ret = hc_init_memory(instance);
     210        CHECK_RET_RETURN(ret, "Failed to create OHCI memory structures: %s.\n",
     211            str_error(ret));
     212#undef CHECK_RET_RETURN
    293213
    294214        fibril_mutex_initialize(&instance->guard);
     
    307227        return EOK;
    308228}
    309 
     229/*----------------------------------------------------------------------------*/
    310230void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)
    311231{
     
    321241        switch (ep->transfer_type) {
    322242        case USB_TRANSFER_CONTROL:
    323                 OHCI_CLR(instance->registers->control, C_CLE);
     243                instance->registers->control &= ~C_CLE;
    324244                endpoint_list_add_ep(list, ohci_ep);
    325                 OHCI_WR(instance->registers->control_current, 0);
    326                 OHCI_SET(instance->registers->control, C_CLE);
     245                instance->registers->control_current = 0;
     246                instance->registers->control |= C_CLE;
    327247                break;
    328248        case USB_TRANSFER_BULK:
    329                 OHCI_CLR(instance->registers->control, C_BLE);
     249                instance->registers->control &= ~C_BLE;
    330250                endpoint_list_add_ep(list, ohci_ep);
    331                 OHCI_WR(instance->registers->bulk_current, 0);
    332                 OHCI_SET(instance->registers->control, C_BLE);
     251                instance->registers->control |= C_BLE;
    333252                break;
    334253        case USB_TRANSFER_ISOCHRONOUS:
    335254        case USB_TRANSFER_INTERRUPT:
    336                 OHCI_CLR(instance->registers->control, C_PLE | C_IE);
     255                instance->registers->control &= (~C_PLE & ~C_IE);
    337256                endpoint_list_add_ep(list, ohci_ep);
    338                 OHCI_SET(instance->registers->control, C_PLE | C_IE);
    339                 break;
    340         }
    341 }
    342 
     257                instance->registers->control |= C_PLE | C_IE;
     258                break;
     259        }
     260}
     261/*----------------------------------------------------------------------------*/
    343262void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep)
    344263{
     
    354273        switch (ep->transfer_type) {
    355274        case USB_TRANSFER_CONTROL:
    356                 OHCI_CLR(instance->registers->control, C_CLE);
     275                instance->registers->control &= ~C_CLE;
    357276                endpoint_list_remove_ep(list, ohci_ep);
    358                 OHCI_WR(instance->registers->control_current, 0);
    359                 OHCI_SET(instance->registers->control, C_CLE);
     277                instance->registers->control_current = 0;
     278                instance->registers->control |= C_CLE;
    360279                break;
    361280        case USB_TRANSFER_BULK:
    362                 OHCI_CLR(instance->registers->control, C_BLE);
     281                instance->registers->control &= ~C_BLE;
    363282                endpoint_list_remove_ep(list, ohci_ep);
    364                 OHCI_WR(instance->registers->bulk_current, 0);
    365                 OHCI_SET(instance->registers->control, C_BLE);
     283                instance->registers->control |= C_BLE;
    366284                break;
    367285        case USB_TRANSFER_ISOCHRONOUS:
    368286        case USB_TRANSFER_INTERRUPT:
    369                 OHCI_CLR(instance->registers->control, C_PLE | C_IE);
     287                instance->registers->control &= (~C_PLE & ~C_IE);
    370288                endpoint_list_remove_ep(list, ohci_ep);
    371                 OHCI_SET(instance->registers->control, C_PLE | C_IE);
     289                instance->registers->control |= C_PLE | C_IE;
    372290                break;
    373291        default:
     
    375293        }
    376294}
    377 
     295/*----------------------------------------------------------------------------*/
    378296/** Add USB transfer to the schedule.
    379297 *
     
    390308        /* Check for root hub communication */
    391309        if (batch->ep->address == instance->rh.address) {
    392                 usb_log_debug("OHCI root hub request.\n");
    393310                rh_request(&instance->rh, batch);
    394311                return EOK;
     
    406323        {
    407324        case USB_TRANSFER_CONTROL:
    408                 OHCI_SET(instance->registers->command_status, CS_CLF);
     325                instance->registers->command_status |= CS_CLF;
    409326                break;
    410327        case USB_TRANSFER_BULK:
    411                 OHCI_SET(instance->registers->command_status, CS_BLF);
     328                instance->registers->command_status |= CS_BLF;
    412329                break;
    413330        default:
     
    417334        return EOK;
    418335}
    419 
     336/*----------------------------------------------------------------------------*/
    420337/** Interrupt handling routine
    421338 *
     
    425342void hc_interrupt(hc_t *instance, uint32_t status)
    426343{
    427         status = OHCI_RD(status);
    428344        assert(instance);
    429345        if ((status & ~I_SF) == 0) /* ignore sof status */
     
    436352                fibril_mutex_lock(&instance->guard);
    437353                usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).\n", instance->hcca,
    438                     OHCI_RD(instance->registers->hcca),
     354                    instance->registers->hcca,
    439355                    (void *) addr_to_phys(instance->hcca));
    440356                usb_log_debug2("Periodic current: %#" PRIx32 ".\n",
    441                     OHCI_RD(instance->registers->periodic_current));
     357                    instance->registers->periodic_current);
    442358
    443359                link_t *current = list_first(&instance->pending_batches);
     
    463379
    464380}
    465 
     381/*----------------------------------------------------------------------------*/
    466382/** Check status register regularly
    467383 *
     
    481397        return EOK;
    482398}
    483 
     399/*----------------------------------------------------------------------------*/
    484400/** Turn off any (BIOS)driver that might be in control of the device.
    485401 *
     
    494410
    495411        usb_log_debug("Requesting OHCI control.\n");
    496         if (OHCI_RD(instance->registers->revision) & R_LEGACY_FLAG) {
     412        if (instance->registers->revision & R_LEGACY_FLAG) {
    497413                /* Turn off legacy emulation, it should be enough to zero
    498414                 * the lowest bit, but it caused problems. Thus clear all
     
    503419                (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
    504420                usb_log_debug("OHCI legacy register %p: %x.\n",
    505                     ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
     421                    ohci_emulation_reg, *ohci_emulation_reg);
    506422                /* Zero everything but A20State */
    507                 OHCI_CLR(*ohci_emulation_reg, ~0x100);
     423                *ohci_emulation_reg &= 0x100;
    508424                usb_log_debug(
    509425                    "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
    510                     ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
     426                    ohci_emulation_reg, *ohci_emulation_reg);
    511427        }
    512428
    513429        /* Interrupt routing enabled => smm driver is active */
    514         if (OHCI_RD(instance->registers->control) & C_IR) {
     430        if (instance->registers->control & C_IR) {
    515431                usb_log_debug("SMM driver: request ownership change.\n");
    516                 OHCI_SET(instance->registers->command_status, CS_OCR);
     432                instance->registers->command_status |= CS_OCR;
    517433                /* Hope that SMM actually knows its stuff or we can hang here */
    518                 while (OHCI_RD(instance->registers->control & C_IR)) {
     434                while (instance->registers->control & C_IR) {
    519435                        async_usleep(1000);
    520436                }
     
    533449                        return;
    534450                }
    535                 /* HC is suspended assert resume for 20ms */
     451                /* HC is suspended assert resume for 20ms, */
    536452                C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
    537453                async_usleep(20000);
     
    545461        async_usleep(50000);
    546462}
    547 
     463/*----------------------------------------------------------------------------*/
    548464/** OHCI hw initialization routine.
    549465 *
     
    557473
    558474        /* Save contents of fm_interval register */
    559         const uint32_t fm_interval = OHCI_RD(instance->registers->fm_interval);
     475        const uint32_t fm_interval = instance->registers->fm_interval;
    560476        usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);
    561477
     
    563479        usb_log_debug2("HC reset.\n");
    564480        size_t time = 0;
    565         OHCI_WR(instance->registers->command_status, CS_HCR);
    566         while (OHCI_RD(instance->registers->command_status) & CS_HCR) {
     481        instance->registers->command_status = CS_HCR;
     482        while (instance->registers->command_status & CS_HCR) {
    567483                async_usleep(10);
    568484                time += 10;
     
    571487
    572488        /* Restore fm_interval */
    573         OHCI_WR(instance->registers->fm_interval, fm_interval);
    574         assert((OHCI_RD(instance->registers->command_status) & CS_HCR) == 0);
     489        instance->registers->fm_interval = fm_interval;
     490        assert((instance->registers->command_status & CS_HCR) == 0);
    575491
    576492        /* hc is now in suspend state */
    577493        usb_log_debug2("HC should be in suspend state(%x).\n",
    578             OHCI_RD(instance->registers->control));
     494            instance->registers->control);
    579495
    580496        /* Use HCCA */
    581         OHCI_WR(instance->registers->hcca, addr_to_phys(instance->hcca));
     497        instance->registers->hcca = addr_to_phys(instance->hcca);
    582498
    583499        /* Use queues */
    584         OHCI_WR(instance->registers->bulk_head,
    585             instance->lists[USB_TRANSFER_BULK].list_head_pa);
     500        instance->registers->bulk_head =
     501            instance->lists[USB_TRANSFER_BULK].list_head_pa;
    586502        usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").\n",
    587503            instance->lists[USB_TRANSFER_BULK].list_head,
    588504            instance->lists[USB_TRANSFER_BULK].list_head_pa);
    589505
    590         OHCI_WR(instance->registers->control_head,
    591             instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
     506        instance->registers->control_head =
     507            instance->lists[USB_TRANSFER_CONTROL].list_head_pa;
    592508        usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").\n",
    593509            instance->lists[USB_TRANSFER_CONTROL].list_head,
     
    595511
    596512        /* Enable queues */
    597         OHCI_SET(instance->registers->control, (C_PLE | C_IE | C_CLE | C_BLE));
    598         usb_log_debug("Queues enabled(%x).\n",
    599             OHCI_RD(instance->registers->control));
     513        instance->registers->control |= (C_PLE | C_IE | C_CLE | C_BLE);
     514        usb_log_debug2("All queues enabled(%x).\n",
     515            instance->registers->control);
    600516
    601517        /* Enable interrupts */
    602         OHCI_WR(instance->registers->interrupt_enable, OHCI_USED_INTERRUPTS);
    603         usb_log_debug("Enabled interrupts: %x.\n",
    604             OHCI_RD(instance->registers->interrupt_enable));
    605         OHCI_WR(instance->registers->interrupt_enable, I_MI);
     518        instance->registers->interrupt_enable = OHCI_USED_INTERRUPTS;
     519        usb_log_debug2("Enabled interrupts: %x.\n",
     520            instance->registers->interrupt_enable);
     521        instance->registers->interrupt_enable = I_MI;
    606522
    607523        /* Set periodic start to 90% */
    608         const uint32_t frame_length =
    609             (fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK;
    610         OHCI_WR(instance->registers->periodic_start,
    611             ((frame_length / 10) * 9) & PS_MASK << PS_SHIFT);
     524        uint32_t frame_length = ((fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK);
     525        instance->registers->periodic_start = (frame_length / 10) * 9;
    612526        usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n",
    613             OHCI_RD(instance->registers->periodic_start),
    614             OHCI_RD(instance->registers->periodic_start), frame_length);
     527            instance->registers->periodic_start,
     528            instance->registers->periodic_start, frame_length);
     529
    615530        C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
    616531        usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
    617             OHCI_RD(instance->registers->control));
    618 }
    619 
     532            instance->registers->control);
     533}
     534/*----------------------------------------------------------------------------*/
    620535/** Initialize schedule queues
    621536 *
     
    651566        return EOK;
    652567}
    653 
     568/*----------------------------------------------------------------------------*/
    654569/** Initialize memory structures used by the OHCI hcd.
    655570 *
     
    661576        assert(instance);
    662577
    663         memset(&instance->rh, 0, sizeof(instance->rh));
     578        bzero(&instance->rh, sizeof(instance->rh));
    664579        /* Init queues */
    665580        const int ret = hc_init_transfer_lists(instance);
     
    672587        if (instance->hcca == NULL)
    673588                return ENOMEM;
     589        bzero(instance->hcca, sizeof(hcca_t));
    674590        usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
    675591
    676         for (unsigned i = 0; i < HCCA_INT_EP_COUNT; ++i) {
    677                 hcca_set_int_ep(instance->hcca, i,
    678                     instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
     592        for (unsigned i = 0; i < 32; ++i) {
     593                instance->hcca->int_ep[i] =
     594                    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa;
    679595        }
    680596        usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").\n",
Note: See TracChangeset for help on using the changeset viewer.