Ignore:
File:
1 edited

Legend:

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

    rd57122c rf83666c  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
     28
    2829/** @addtogroup drvusbohcihc
    2930 * @{
     
    3233 * @brief OHCI Host controller driver routines
    3334 */
     35
    3436#include <errno.h>
     37#include <stdbool.h>
    3538#include <str_error.h>
    3639#include <adt/list.h>
     
    4952static const irq_pio_range_t ohci_pio_ranges[] = {
    5053        {
    51                 .base = 0,      /* filled later */
     54                .base = 0,
    5255                .size = sizeof(ohci_regs_t)
    5356        }
     
    5558
    5659static const irq_cmd_t ohci_irq_commands[] = {
    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 },
     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
     86enum {
     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)
    6294};
    6395
     
    68100static int interrupt_emulator(hc_t *instance);
    69101static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
    70 /*----------------------------------------------------------------------------*/
    71 /** Get number of PIO ranges used in IRQ code.
    72  * @return Number of ranges.
    73  */
    74 size_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  */
    83 size_t hc_irq_cmd_count(void)
    84 {
    85         return sizeof(ohci_irq_commands) / sizeof(irq_cmd_t);
    86 }
    87 /*----------------------------------------------------------------------------*/
     102
    88103/** Generate IRQ code.
    89104 * @param[out] ranges PIO ranges buffer.
     
    112127        cmds[0].addr = (void *) &registers->interrupt_status;
    113128        cmds[3].addr = (void *) &registers->interrupt_status;
    114 
    115         return EOK;
    116 }
    117 /*----------------------------------------------------------------------------*/
     129        OHCI_WR(cmds[1].value, OHCI_USED_INTERRUPTS);
     130
     131        return EOK;
     132}
     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 */
     144int 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
    118178/** Announce OHCI root hub to the DDF
    119179 *
     
    124184int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun)
    125185{
     186        bool addr_reqd = false;
     187        bool ep_added = false;
     188        bool fun_bound = false;
     189        int rc;
     190
    126191        assert(instance);
    127192        assert(hub_fun);
     
    129194        /* Try to get address 1 for root hub. */
    130195        instance->rh.address = 1;
    131         int ret = usb_device_manager_request_address(
     196        rc = usb_device_manager_request_address(
    132197            &instance->generic.dev_manager, &instance->rh.address, false,
    133198            USB_SPEED_FULL);
    134         if (ret != EOK) {
     199        if (rc != EOK) {
    135200                usb_log_error("Failed to get OHCI root hub address: %s\n",
    136                     str_error(ret));
    137                 return ret;
    138         }
    139 
    140 #define CHECK_RET_UNREG_RETURN(ret, message...) \
    141 if (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(
     201                    str_error(rc));
     202                goto error;
     203        }
     204
     205        addr_reqd = true;
     206
     207        rc = usb_endpoint_manager_add_ep(
    152208            &instance->generic.ep_manager, instance->rh.address, 0,
    153209            USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64,
    154210            0, NULL, NULL);
    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)
     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) {
    170238                usb_log_warning("Failed to bind root hub address: %s.\n",
    171                     str_error(ret));
    172 
    173         return EOK;
    174 #undef CHECK_RET_RELEASE
    175 }
    176 /*----------------------------------------------------------------------------*/
     239                    str_error(rc));
     240        }
     241
     242        return EOK;
     243error:
     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
    177258/** Initialize OHCI hc driver structure
    178259 *
     
    187268        assert(instance);
    188269
    189 #define CHECK_RET_RETURN(ret, message...) \
    190 if (ret != EOK) { \
    191         usb_log_error(message); \
    192         return ret; \
    193 } else (void)0
    194 
    195         int ret =
     270        int rc =
    196271            pio_enable((void*)regs, reg_size, (void**)&instance->registers);
    197         CHECK_RET_RETURN(ret,
    198             "Failed to gain access to device registers: %s.\n", str_error(ret));
     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        }
    199277
    200278        list_initialize(&instance->pending_batches);
     
    207285        instance->generic.ep_remove_hook = ohci_endpoint_fini;
    208286
    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
     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        }
    213293
    214294        fibril_mutex_initialize(&instance->guard);
     
    227307        return EOK;
    228308}
    229 /*----------------------------------------------------------------------------*/
     309
    230310void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)
    231311{
     
    241321        switch (ep->transfer_type) {
    242322        case USB_TRANSFER_CONTROL:
    243                 instance->registers->control &= ~C_CLE;
     323                OHCI_CLR(instance->registers->control, C_CLE);
    244324                endpoint_list_add_ep(list, ohci_ep);
    245                 instance->registers->control_current = 0;
    246                 instance->registers->control |= C_CLE;
     325                OHCI_WR(instance->registers->control_current, 0);
     326                OHCI_SET(instance->registers->control, C_CLE);
    247327                break;
    248328        case USB_TRANSFER_BULK:
    249                 instance->registers->control &= ~C_BLE;
     329                OHCI_CLR(instance->registers->control, C_BLE);
    250330                endpoint_list_add_ep(list, ohci_ep);
    251                 instance->registers->control |= C_BLE;
     331                OHCI_WR(instance->registers->bulk_current, 0);
     332                OHCI_SET(instance->registers->control, C_BLE);
    252333                break;
    253334        case USB_TRANSFER_ISOCHRONOUS:
    254335        case USB_TRANSFER_INTERRUPT:
    255                 instance->registers->control &= (~C_PLE & ~C_IE);
     336                OHCI_CLR(instance->registers->control, C_PLE | C_IE);
    256337                endpoint_list_add_ep(list, ohci_ep);
    257                 instance->registers->control |= C_PLE | C_IE;
    258                 break;
    259         }
    260 }
    261 /*----------------------------------------------------------------------------*/
     338                OHCI_SET(instance->registers->control, C_PLE | C_IE);
     339                break;
     340        }
     341}
     342
    262343void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep)
    263344{
     
    273354        switch (ep->transfer_type) {
    274355        case USB_TRANSFER_CONTROL:
    275                 instance->registers->control &= ~C_CLE;
     356                OHCI_CLR(instance->registers->control, C_CLE);
    276357                endpoint_list_remove_ep(list, ohci_ep);
    277                 instance->registers->control_current = 0;
    278                 instance->registers->control |= C_CLE;
     358                OHCI_WR(instance->registers->control_current, 0);
     359                OHCI_SET(instance->registers->control, C_CLE);
    279360                break;
    280361        case USB_TRANSFER_BULK:
    281                 instance->registers->control &= ~C_BLE;
     362                OHCI_CLR(instance->registers->control, C_BLE);
    282363                endpoint_list_remove_ep(list, ohci_ep);
    283                 instance->registers->control |= C_BLE;
     364                OHCI_WR(instance->registers->bulk_current, 0);
     365                OHCI_SET(instance->registers->control, C_BLE);
    284366                break;
    285367        case USB_TRANSFER_ISOCHRONOUS:
    286368        case USB_TRANSFER_INTERRUPT:
    287                 instance->registers->control &= (~C_PLE & ~C_IE);
     369                OHCI_CLR(instance->registers->control, C_PLE | C_IE);
    288370                endpoint_list_remove_ep(list, ohci_ep);
    289                 instance->registers->control |= C_PLE | C_IE;
     371                OHCI_SET(instance->registers->control, C_PLE | C_IE);
    290372                break;
    291373        default:
     
    293375        }
    294376}
    295 /*----------------------------------------------------------------------------*/
     377
    296378/** Add USB transfer to the schedule.
    297379 *
     
    308390        /* Check for root hub communication */
    309391        if (batch->ep->address == instance->rh.address) {
     392                usb_log_debug("OHCI root hub request.\n");
    310393                rh_request(&instance->rh, batch);
    311394                return EOK;
     
    323406        {
    324407        case USB_TRANSFER_CONTROL:
    325                 instance->registers->command_status |= CS_CLF;
     408                OHCI_SET(instance->registers->command_status, CS_CLF);
    326409                break;
    327410        case USB_TRANSFER_BULK:
    328                 instance->registers->command_status |= CS_BLF;
     411                OHCI_SET(instance->registers->command_status, CS_BLF);
    329412                break;
    330413        default:
     
    334417        return EOK;
    335418}
    336 /*----------------------------------------------------------------------------*/
     419
    337420/** Interrupt handling routine
    338421 *
     
    342425void hc_interrupt(hc_t *instance, uint32_t status)
    343426{
     427        status = OHCI_RD(status);
    344428        assert(instance);
    345429        if ((status & ~I_SF) == 0) /* ignore sof status */
     
    352436                fibril_mutex_lock(&instance->guard);
    353437                usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).\n", instance->hcca,
    354                     instance->registers->hcca,
     438                    OHCI_RD(instance->registers->hcca),
    355439                    (void *) addr_to_phys(instance->hcca));
    356440                usb_log_debug2("Periodic current: %#" PRIx32 ".\n",
    357                     instance->registers->periodic_current);
     441                    OHCI_RD(instance->registers->periodic_current));
    358442
    359443                link_t *current = list_first(&instance->pending_batches);
     
    379463
    380464}
    381 /*----------------------------------------------------------------------------*/
     465
    382466/** Check status register regularly
    383467 *
     
    397481        return EOK;
    398482}
    399 /*----------------------------------------------------------------------------*/
     483
    400484/** Turn off any (BIOS)driver that might be in control of the device.
    401485 *
     
    410494
    411495        usb_log_debug("Requesting OHCI control.\n");
    412         if (instance->registers->revision & R_LEGACY_FLAG) {
     496        if (OHCI_RD(instance->registers->revision) & R_LEGACY_FLAG) {
    413497                /* Turn off legacy emulation, it should be enough to zero
    414498                 * the lowest bit, but it caused problems. Thus clear all
     
    419503                (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
    420504                usb_log_debug("OHCI legacy register %p: %x.\n",
    421                     ohci_emulation_reg, *ohci_emulation_reg);
     505                    ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
    422506                /* Zero everything but A20State */
    423                 *ohci_emulation_reg &= 0x100;
     507                OHCI_CLR(*ohci_emulation_reg, ~0x100);
    424508                usb_log_debug(
    425509                    "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
    426                     ohci_emulation_reg, *ohci_emulation_reg);
     510                    ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
    427511        }
    428512
    429513        /* Interrupt routing enabled => smm driver is active */
    430         if (instance->registers->control & C_IR) {
     514        if (OHCI_RD(instance->registers->control) & C_IR) {
    431515                usb_log_debug("SMM driver: request ownership change.\n");
    432                 instance->registers->command_status |= CS_OCR;
     516                OHCI_SET(instance->registers->command_status, CS_OCR);
    433517                /* Hope that SMM actually knows its stuff or we can hang here */
    434                 while (instance->registers->control & C_IR) {
     518                while (OHCI_RD(instance->registers->control & C_IR)) {
    435519                        async_usleep(1000);
    436520                }
     
    449533                        return;
    450534                }
    451                 /* HC is suspended assert resume for 20ms, */
     535                /* HC is suspended assert resume for 20ms */
    452536                C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
    453537                async_usleep(20000);
     
    461545        async_usleep(50000);
    462546}
    463 /*----------------------------------------------------------------------------*/
     547
    464548/** OHCI hw initialization routine.
    465549 *
     
    473557
    474558        /* Save contents of fm_interval register */
    475         const uint32_t fm_interval = instance->registers->fm_interval;
     559        const uint32_t fm_interval = OHCI_RD(instance->registers->fm_interval);
    476560        usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);
    477561
     
    479563        usb_log_debug2("HC reset.\n");
    480564        size_t time = 0;
    481         instance->registers->command_status = CS_HCR;
    482         while (instance->registers->command_status & CS_HCR) {
     565        OHCI_WR(instance->registers->command_status, CS_HCR);
     566        while (OHCI_RD(instance->registers->command_status) & CS_HCR) {
    483567                async_usleep(10);
    484568                time += 10;
     
    487571
    488572        /* Restore fm_interval */
    489         instance->registers->fm_interval = fm_interval;
    490         assert((instance->registers->command_status & CS_HCR) == 0);
     573        OHCI_WR(instance->registers->fm_interval, fm_interval);
     574        assert((OHCI_RD(instance->registers->command_status) & CS_HCR) == 0);
    491575
    492576        /* hc is now in suspend state */
    493577        usb_log_debug2("HC should be in suspend state(%x).\n",
    494             instance->registers->control);
     578            OHCI_RD(instance->registers->control));
    495579
    496580        /* Use HCCA */
    497         instance->registers->hcca = addr_to_phys(instance->hcca);
     581        OHCI_WR(instance->registers->hcca, addr_to_phys(instance->hcca));
    498582
    499583        /* Use queues */
    500         instance->registers->bulk_head =
    501             instance->lists[USB_TRANSFER_BULK].list_head_pa;
     584        OHCI_WR(instance->registers->bulk_head,
     585            instance->lists[USB_TRANSFER_BULK].list_head_pa);
    502586        usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").\n",
    503587            instance->lists[USB_TRANSFER_BULK].list_head,
    504588            instance->lists[USB_TRANSFER_BULK].list_head_pa);
    505589
    506         instance->registers->control_head =
    507             instance->lists[USB_TRANSFER_CONTROL].list_head_pa;
     590        OHCI_WR(instance->registers->control_head,
     591            instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
    508592        usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").\n",
    509593            instance->lists[USB_TRANSFER_CONTROL].list_head,
     
    511595
    512596        /* Enable queues */
    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);
     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));
    516600
    517601        /* Enable interrupts */
    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;
     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);
    522606
    523607        /* Set periodic start to 90% */
    524         uint32_t frame_length = ((fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK);
    525         instance->registers->periodic_start = (frame_length / 10) * 9;
     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);
    526612        usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n",
    527             instance->registers->periodic_start,
    528             instance->registers->periodic_start, frame_length);
    529 
     613            OHCI_RD(instance->registers->periodic_start),
     614            OHCI_RD(instance->registers->periodic_start), frame_length);
    530615        C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
    531616        usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
    532             instance->registers->control);
    533 }
    534 /*----------------------------------------------------------------------------*/
     617            OHCI_RD(instance->registers->control));
     618}
     619
    535620/** Initialize schedule queues
    536621 *
     
    566651        return EOK;
    567652}
    568 /*----------------------------------------------------------------------------*/
     653
    569654/** Initialize memory structures used by the OHCI hcd.
    570655 *
     
    576661        assert(instance);
    577662
    578         bzero(&instance->rh, sizeof(instance->rh));
     663        memset(&instance->rh, 0, sizeof(instance->rh));
    579664        /* Init queues */
    580665        const int ret = hc_init_transfer_lists(instance);
     
    587672        if (instance->hcca == NULL)
    588673                return ENOMEM;
    589         bzero(instance->hcca, sizeof(hcca_t));
    590674        usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
    591675
    592         for (unsigned i = 0; i < 32; ++i) {
    593                 instance->hcca->int_ep[i] =
    594                     instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa;
     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);
    595679        }
    596680        usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").\n",
Note: See TracChangeset for help on using the changeset viewer.