Ignore:
File:
1 edited

Legend:

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

    ref9460b 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));
    152 
    153         ret = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100);
    154         CHECK_RET_RELEASE(ret,
    155             "Failed to add root hub match-id: %s.\n", str_error(ret));
     85        CHECK_RET_RELEASE(ret, "Failed(%d) to add OHCI rh endpoint 0.\n", ret);
     86
     87        char *match_str = NULL;
     88        /* DDF needs heap allocated string */
     89        ret = asprintf(&match_str, "usb&class=hub");
     90        ret = ret > 0 ? 0 : ret;
     91        CHECK_RET_RELEASE(ret, "Failed(%d) to create match-id string.\n", ret);
     92
     93        ret = ddf_fun_add_match_id(hub_fun, match_str, 100);
     94        CHECK_RET_RELEASE(ret, "Failed(%d) add root hub match-id.\n", ret);
    15695
    15796        ret = ddf_fun_bind(hub_fun);
    158         CHECK_RET_RELEASE(ret,
    159             "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);
    16098
    16199        return EOK;
     
    174112{
    175113        assert(instance);
    176 
     114        int ret = EOK;
    177115#define CHECK_RET_RETURN(ret, message...) \
    178116if (ret != EOK) { \
     
    181119} else (void)0
    182120
    183         int ret =
    184             pio_enable((void*)regs, reg_size, (void**)&instance->registers);
     121        ret = pio_enable((void*)regs, reg_size, (void**)&instance->registers);
    185122        CHECK_RET_RETURN(ret,
    186             "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));
    187125
    188126        list_initialize(&instance->pending_batches);
    189127        usb_device_keeper_init(&instance->manager);
    190 
    191128        ret = usb_endpoint_manager_init(&instance->ep_manager,
    192129            BANDWIDTH_AVAILABLE_USB11);
     
    200137
    201138        fibril_mutex_initialize(&instance->guard);
    202 
    203139        hc_gain_control(instance);
     140
     141        rh_init(&instance->rh, instance->registers);
    204142
    205143        if (!interrupts) {
     
    209147        }
    210148
    211         rh_init(&instance->rh, instance->registers);
    212         hc_start(instance);
    213 
    214149        return EOK;
    215150}
    216151/*----------------------------------------------------------------------------*/
    217 /** Create and register endpoint structures.
     152/** Create end register endpoint structures
    218153 *
    219154 * @param[in] instance OHCI driver structure.
     
    233168    size_t mps, size_t size, unsigned interval)
    234169{
    235         endpoint_t *ep =
    236             endpoint_get(address, endpoint, direction, type, speed, mps);
     170        endpoint_t *ep = malloc(sizeof(endpoint_t));
    237171        if (ep == NULL)
    238172                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        }
    239179
    240180        hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);
     
    244184        }
    245185
    246         int ret =
    247             usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
     186        ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
    248187        if (ret != EOK) {
    249188                hcd_endpoint_clear(ep);
     
    273212                    &instance->lists[ep->transfer_type], hcd_ep);
    274213                instance->registers->control |= C_PLE | C_IE;
     214                break;
     215        default:
    275216                break;
    276217        }
     
    371312        /* Check for root hub communication */
    372313        if (batch->ep->address == instance->rh.address) {
    373                 rh_request(&instance->rh, batch);
    374                 return EOK;
     314                return rh_request(&instance->rh, batch);
    375315        }
    376316
     
    434374
    435375        if (status & I_UE) {
    436                 hc_start(instance);
     376                hc_start_hw(instance);
    437377        }
    438378
     
    459399/** Turn off any (BIOS)driver that might be in control of the device.
    460400 *
    461  * This function implements routines described in chapter 5.1.1.3 of the OHCI
    462  * specification (page 40, pdf page 54).
    463  *
    464401 * @param[in] instance OHCI hc driver structure.
    465402 */
     
    467404{
    468405        assert(instance);
    469 
    470406        usb_log_debug("Requesting OHCI control.\n");
    471         if (instance->registers->revision & R_LEGACY_FLAG) {
    472                 /* Turn off legacy emulation, it should be enough to zero
    473                  * the lowest bit, but it caused problems. Thus clear all
    474                  * except GateA20 (causes restart on some hw).
    475                  * See page 145 of the specs for details.
    476                  */
    477                 volatile uint32_t *ohci_emulation_reg =
    478                 (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
    479                 usb_log_debug("OHCI legacy register %p: %x.\n",
    480                     ohci_emulation_reg, *ohci_emulation_reg);
    481                 /* Zero everything but A20State */
    482                 *ohci_emulation_reg &= 0x100;
    483                 usb_log_debug(
    484                     "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
    485                     ohci_emulation_reg, *ohci_emulation_reg);
    486         }
     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);
    487416
    488417        /* Interrupt routing enabled => smm driver is active */
     
    490419                usb_log_debug("SMM driver: request ownership change.\n");
    491420                instance->registers->command_status |= CS_OCR;
    492                 /* Hope that SMM actually knows its stuff or we can hang here */
    493421                while (instance->registers->control & C_IR) {
    494422                        async_usleep(1000);
    495423                }
    496424                usb_log_info("SMM driver: Ownership taken.\n");
    497                 C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
     425                instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT);
    498426                async_usleep(50000);
    499427                return;
    500428        }
    501429
    502         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;
    503432        /* Interrupt routing disabled && status != USB_RESET => BIOS active */
    504433        if (hc_status != C_HCFS_RESET) {
     
    508437                        return;
    509438                }
    510                 /* HC is suspended assert resume for 20ms, */
    511                 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);
    512441                async_usleep(20000);
    513442                usb_log_info("BIOS driver: HC resumed.\n");
     
    525454 * @param[in] instance OHCI hc driver structure.
    526455 */
    527 void hc_start(hc_t *instance)
     456void hc_start_hw(hc_t *instance)
    528457{
    529458        /* OHCI guide page 42 */
     
    587516            instance->registers->periodic_start, frame_length);
    588517
    589         C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
     518        instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
    590519        usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
    591520            instance->registers->control);
     
    605534        int ret = endpoint_list_init(&instance->lists[type], name); \
    606535        if (ret != EOK) { \
    607                 usb_log_error("Failed to setup %s endpoint list: %s.\n", \
    608                     name, str_error(ret)); \
     536                usb_log_error("Failed(%d) to setup %s endpoint list.\n", \
     537                    ret, name); \
    609538                endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
    610539                endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \
     
    658587            instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    659588
     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
    660621        return EOK;
    661622}
    662 
    663623/**
    664624 * @}
Note: See TracChangeset for help on using the changeset viewer.