Ignore:
File:
1 edited

Legend:

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

    r5d36062 r5203e256  
    4646#define OHCI_USED_INTERRUPTS \
    4747    (I_SO | I_WDH | I_UE | I_RHSC)
    48 
    49 static const irq_cmd_t ohci_irq_commands[] =
    50 {
    51         { .cmd = CMD_MEM_READ_32, .dstarg = 1, .addr = NULL /*filled later*/ },
    52         { .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2, .value = OHCI_USED_INTERRUPTS },
    53         { .cmd = CMD_PREDICATE, .srcarg = 2, .value = 2 },
    54         { .cmd = CMD_MEM_WRITE_A_32, .srcarg = 1, .addr = NULL /*filled later*/ },
    55         { .cmd = CMD_ACCEPT },
    56 };
    57 
     48static int interrupt_emulator(hc_t *instance);
    5849static void hc_gain_control(hc_t *instance);
    59 static void hc_start(hc_t *instance);
    6050static int hc_init_transfer_lists(hc_t *instance);
    6151static int hc_init_memory(hc_t *instance);
    62 static int interrupt_emulator(hc_t *instance);
    63 
    64 /*----------------------------------------------------------------------------*/
    65 /** Get number of commands used in IRQ code.
    66  * @return Number of commands.
    67  */
    68 size_t hc_irq_cmd_count(void)
    69 {
    70         return sizeof(ohci_irq_commands) / sizeof(irq_cmd_t);
    71 }
    72 /*----------------------------------------------------------------------------*/
    73 /** Generate IRQ code commands.
    74  * @param[out] cmds Place to store the commands.
    75  * @param[in] cmd_size Size of the place (bytes).
    76  * @param[in] regs Physical address of device's registers.
    77  * @param[in] reg_size Size of the register area (bytes).
    78  *
    79  * @return Error code.
    80  */
    81 int hc_get_irq_commands(
    82     irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size)
    83 {
    84         if (cmd_size < sizeof(ohci_irq_commands)
    85             || reg_size < sizeof(ohci_regs_t))
    86                 return EOVERFLOW;
    87 
    88         /* Create register mapping to use in IRQ handler.
    89          * This mapping should be present in kernel only.
    90          * Remove it from here when kernel knows how to create mappings
    91          * and accepts physical addresses in IRQ code.
    92          * TODO: remove */
    93         ohci_regs_t *registers;
    94         const int ret = pio_enable((void*)regs, reg_size, (void**)&registers);
    95         if (ret != EOK)
    96                 return ret;
    97 
    98         /* Some bogus access to force create mapping. DO NOT remove,
    99          * unless whole virtual addresses in irq is replaced
    100          * NOTE: Compiler won't remove this as ohci_regs_t members
    101          * are declared volatile.
    102          *
    103          * Introducing CMD_MEM set of IRQ code commands broke
    104          * assumption that IRQ code does not cause page faults.
    105          * If this happens during idling (THREAD == NULL)
    106          * it causes kernel panic.
    107          */
    108         registers->revision;
    109 
    110         memcpy(cmds, ohci_irq_commands, sizeof(ohci_irq_commands));
    111 
    112         void *address = (void*)&registers->interrupt_status;
    113         cmds[0].addr = address;
    114         cmds[3].addr = address;
    115         return EOK;
    116 }
    11752/*----------------------------------------------------------------------------*/
    11853/** Announce OHCI root hub to the DDF
     
    14883        int ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL,
    14984            USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0);
    150         CHECK_RET_RELEASE(ret,
    151             "Failed to add OHCI root hub endpoint 0: %s.\n", str_error(ret));
     85        CHECK_RET_RELEASE(ret, "Failed(%d) to add OHCI rh endpoint 0.\n", ret);
    15286
    15387        char *match_str = NULL;
    154         /* DDF needs heap allocated string. */
     88        /* DDF needs heap allocated string */
    15589        ret = asprintf(&match_str, "usb&class=hub");
    15690        ret = ret > 0 ? 0 : ret;
    157         CHECK_RET_RELEASE(ret,
    158             "Failed to create match-id string: %s.\n", str_error(ret));
     91        CHECK_RET_RELEASE(ret, "Failed(%d) to create match-id string.\n", ret);
    15992
    16093        ret = ddf_fun_add_match_id(hub_fun, match_str, 100);
    161         CHECK_RET_RELEASE(ret,
    162             "Failed to add root hub match-id: %s.\n", str_error(ret));
     94        CHECK_RET_RELEASE(ret, "Failed(%d) add root hub match-id.\n", ret);
    16395
    16496        ret = ddf_fun_bind(hub_fun);
    165         CHECK_RET_RELEASE(ret,
    166             "Failed to bind root hub function: %s.\n", str_error(ret));
     97        CHECK_RET_RELEASE(ret, "Failed(%d) to bind root hub function.\n", ret);
    16798
    16899        return EOK;
     
    181112{
    182113        assert(instance);
    183 
     114        int ret = EOK;
    184115#define CHECK_RET_RETURN(ret, message...) \
    185116if (ret != EOK) { \
     
    188119} else (void)0
    189120
    190         int ret =
    191             pio_enable((void*)regs, reg_size, (void**)&instance->registers);
     121        ret = pio_enable((void*)regs, reg_size, (void**)&instance->registers);
    192122        CHECK_RET_RETURN(ret,
    193             "Failed to gain access to device registers: %s.\n", str_error(ret));
     123            "Failed(%d) to gain access to device registers: %s.\n",
     124            ret, str_error(ret));
    194125
    195126        list_initialize(&instance->pending_batches);
    196127        usb_device_keeper_init(&instance->manager);
    197 
    198128        ret = usb_endpoint_manager_init(&instance->ep_manager,
    199129            BANDWIDTH_AVAILABLE_USB11);
     
    207137
    208138        fibril_mutex_initialize(&instance->guard);
    209 
    210139        hc_gain_control(instance);
     140
     141        rh_init(&instance->rh, instance->registers);
    211142
    212143        if (!interrupts) {
     
    216147        }
    217148
    218         rh_init(&instance->rh, instance->registers);
    219         hc_start(instance);
    220 
    221149        return EOK;
    222150}
    223151/*----------------------------------------------------------------------------*/
    224 /** Create and register endpoint structures.
     152/** Create end register endpoint structures
    225153 *
    226154 * @param[in] instance OHCI driver structure.
     
    240168    size_t mps, size_t size, unsigned interval)
    241169{
    242         endpoint_t *ep =
    243             endpoint_get(address, endpoint, direction, type, speed, mps);
     170        endpoint_t *ep = malloc(sizeof(endpoint_t));
    244171        if (ep == NULL)
    245172                return ENOMEM;
     173        int ret =
     174            endpoint_init(ep, address, endpoint, direction, type, speed, mps);
     175        if (ret != EOK) {
     176                free(ep);
     177                return ret;
     178        }
    246179
    247180        hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);
     
    251184        }
    252185
    253         int ret =
    254             usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
     186        ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
    255187        if (ret != EOK) {
    256188                hcd_endpoint_clear(ep);
     
    280212                    &instance->lists[ep->transfer_type], hcd_ep);
    281213                instance->registers->control |= C_PLE | C_IE;
     214                break;
     215        default:
    282216                break;
    283217        }
     
    378312        /* Check for root hub communication */
    379313        if (batch->ep->address == instance->rh.address) {
    380                 rh_request(&instance->rh, batch);
    381                 return EOK;
     314                return rh_request(&instance->rh, batch);
    382315        }
    383316
     
    441374
    442375        if (status & I_UE) {
    443                 hc_start(instance);
     376                hc_start_hw(instance);
    444377        }
    445378
     
    466399/** Turn off any (BIOS)driver that might be in control of the device.
    467400 *
    468  * This function implements routines described in chapter 5.1.1.3 of the OHCI
    469  * specification (page 40, pdf page 54).
    470  *
    471401 * @param[in] instance OHCI hc driver structure.
    472402 */
     
    474404{
    475405        assert(instance);
    476 
    477406        usb_log_debug("Requesting OHCI control.\n");
    478         if (instance->registers->revision & R_LEGACY_FLAG) {
    479                 /* Turn off legacy emulation, it should be enough to zero
    480                  * the lowest bit, but it caused problems. Thus clear all
    481                  * except GateA20 (causes restart on some hw).
    482                  * See page 145 of the specs for details.
    483                  */
    484                 volatile uint32_t *ohci_emulation_reg =
    485                 (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
    486                 usb_log_debug("OHCI legacy register %p: %x.\n",
    487                     ohci_emulation_reg, *ohci_emulation_reg);
    488                 /* Zero everything but A20State */
    489                 *ohci_emulation_reg &= 0x100;
    490                 usb_log_debug(
    491                     "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
    492                     ohci_emulation_reg, *ohci_emulation_reg);
    493         }
     407        /* Turn off legacy emulation */
     408        volatile uint32_t *ohci_emulation_reg =
     409            (uint32_t*)((char*)instance->registers + 0x100);
     410        usb_log_debug("OHCI legacy register %p: %x.\n",
     411            ohci_emulation_reg, *ohci_emulation_reg);
     412        /* Do not change A20 state */
     413        *ohci_emulation_reg &= 0x100;
     414        usb_log_debug("OHCI legacy register %p: %x.\n",
     415            ohci_emulation_reg, *ohci_emulation_reg);
    494416
    495417        /* Interrupt routing enabled => smm driver is active */
     
    497419                usb_log_debug("SMM driver: request ownership change.\n");
    498420                instance->registers->command_status |= CS_OCR;
    499                 /* Hope that SMM actually knows its stuff or we can hang here */
    500421                while (instance->registers->control & C_IR) {
    501422                        async_usleep(1000);
    502423                }
    503424                usb_log_info("SMM driver: Ownership taken.\n");
    504                 C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
     425                instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT);
    505426                async_usleep(50000);
    506427                return;
    507428        }
    508429
    509         const unsigned hc_status = C_HCFS_GET(instance->registers->control);
     430        const unsigned hc_status =
     431            (instance->registers->control >> C_HCFS_SHIFT) & C_HCFS_MASK;
    510432        /* Interrupt routing disabled && status != USB_RESET => BIOS active */
    511433        if (hc_status != C_HCFS_RESET) {
     
    515437                        return;
    516438                }
    517                 /* HC is suspended assert resume for 20ms, */
    518                 C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
     439                /* HC is suspended assert resume for 20ms */
     440                instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);
    519441                async_usleep(20000);
    520442                usb_log_info("BIOS driver: HC resumed.\n");
     
    532454 * @param[in] instance OHCI hc driver structure.
    533455 */
    534 void hc_start(hc_t *instance)
     456void hc_start_hw(hc_t *instance)
    535457{
    536458        /* OHCI guide page 42 */
     
    594516            instance->registers->periodic_start, frame_length);
    595517
    596         C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
     518        instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
    597519        usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
    598520            instance->registers->control);
     
    612534        int ret = endpoint_list_init(&instance->lists[type], name); \
    613535        if (ret != EOK) { \
    614                 usb_log_error("Failed to setup %s endpoint list: %s.\n", \
    615                     name, str_error(ret)); \
     536                usb_log_error("Failed(%d) to setup %s endpoint list.\n", \
     537                    ret, name); \
    616538                endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
    617539                endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \
     
    665587            instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    666588
     589        /* Init interrupt code */
     590        instance->interrupt_code.cmds = instance->interrupt_commands;
     591        instance->interrupt_code.cmdcount = OHCI_NEEDED_IRQ_COMMANDS;
     592        {
     593                /* Read status register */
     594                instance->interrupt_commands[0].cmd = CMD_MEM_READ_32;
     595                instance->interrupt_commands[0].dstarg = 1;
     596                instance->interrupt_commands[0].addr =
     597                    (void*)&instance->registers->interrupt_status;
     598
     599                /* Test whether we are the interrupt cause */
     600                instance->interrupt_commands[1].cmd = CMD_BTEST;
     601                instance->interrupt_commands[1].value =
     602                    OHCI_USED_INTERRUPTS;
     603                instance->interrupt_commands[1].srcarg = 1;
     604                instance->interrupt_commands[1].dstarg = 2;
     605
     606                /* Predicate cleaning and accepting */
     607                instance->interrupt_commands[2].cmd = CMD_PREDICATE;
     608                instance->interrupt_commands[2].value = 2;
     609                instance->interrupt_commands[2].srcarg = 2;
     610
     611                /* Write-clean status register */
     612                instance->interrupt_commands[3].cmd = CMD_MEM_WRITE_A_32;
     613                instance->interrupt_commands[3].srcarg = 1;
     614                instance->interrupt_commands[3].addr =
     615                    (void*)&instance->registers->interrupt_status;
     616
     617                /* Accept interrupt */
     618                instance->interrupt_commands[4].cmd = CMD_ACCEPT;
     619        }
     620
    667621        return EOK;
    668622}
    669 
    670623/**
    671624 * @}
Note: See TracChangeset for help on using the changeset viewer.