Beispiel #1
0
int sb_enable_interrupts(ddf_dev_t *device)
{
	async_sess_t *parent_sess = devman_parent_device_connect(
	    ddf_dev_get_handle(device), IPC_FLAG_BLOCKING);
	if (!parent_sess)
		return ENOMEM;

	bool enabled = hw_res_enable_interrupt(parent_sess);
	async_hangup(parent_sess);

	return enabled ? EOK : EIO;
}
Beispiel #2
0
/** Initialize i8042 driver structure.
 *
 * @param dev       Driver structure to initialize.
 * @param regs      I/O address of registers.
 * @param reg_size  size of the reserved I/O address space.
 * @param irq_kbd   IRQ for primary port.
 * @param irq_mouse IRQ for aux port.
 * @param ddf_dev   DDF device structure of the device.
 *
 * @return Error code.
 *
 */
int i8042_init(i8042_t *dev, void *regs, size_t reg_size, int irq_kbd,
               int irq_mouse, ddf_dev_t *ddf_dev)
{
    const size_t range_count = sizeof(i8042_ranges) /
                               sizeof(irq_pio_range_t);
    irq_pio_range_t ranges[range_count];
    const size_t cmd_count = sizeof(i8042_cmds) / sizeof(irq_cmd_t);
    irq_cmd_t cmds[cmd_count];

    int rc;
    bool kbd_bound = false;
    bool aux_bound = false;

    dev->kbd_fun = NULL;
    dev->aux_fun = NULL;

    if (reg_size < sizeof(i8042_regs_t)) {
        rc = EINVAL;
        goto error;
    }

    if (pio_enable(regs, sizeof(i8042_regs_t), (void **) &dev->regs) != 0) {
        rc = EIO;
        goto error;
    }

    dev->kbd_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2a");
    if (dev->kbd_fun == NULL) {
        rc = ENOMEM;
        goto error;
    };

    rc = ddf_fun_add_match_id(dev->kbd_fun, "char/xtkbd", 90);
    if (rc != EOK)
        goto error;

    dev->aux_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2b");
    if (dev->aux_fun == NULL) {
        rc = ENOMEM;
        goto error;
    }

    rc = ddf_fun_add_match_id(dev->aux_fun, "char/ps2mouse", 90);
    if (rc != EOK)
        goto error;

    ddf_fun_set_ops(dev->kbd_fun, &ops);
    ddf_fun_set_ops(dev->aux_fun, &ops);

    buffer_init(&dev->kbd_buffer, dev->kbd_data, BUFFER_SIZE);
    buffer_init(&dev->aux_buffer, dev->aux_data, BUFFER_SIZE);
    fibril_mutex_initialize(&dev->write_guard);

    rc = ddf_fun_bind(dev->kbd_fun);
    if (rc != EOK) {
        ddf_msg(LVL_ERROR, "Failed to bind keyboard function: %s.",
                ddf_fun_get_name(dev->kbd_fun));
        goto error;
    }
    kbd_bound = true;

    rc = ddf_fun_bind(dev->aux_fun);
    if (rc != EOK) {
        ddf_msg(LVL_ERROR, "Failed to bind aux function: %s.",
                ddf_fun_get_name(dev->aux_fun));
        goto error;
    }
    aux_bound = true;

    /* Disable kbd and aux */
    wait_ready(dev);
    pio_write_8(&dev->regs->status, i8042_CMD_WRITE_CMDB);
    wait_ready(dev);
    pio_write_8(&dev->regs->data, i8042_KBD_DISABLE | i8042_AUX_DISABLE);

    /* Flush all current IO */
    while (pio_read_8(&dev->regs->status) & i8042_OUTPUT_FULL)
        (void) pio_read_8(&dev->regs->data);

    memcpy(ranges, i8042_ranges, sizeof(i8042_ranges));
    ranges[0].base = (uintptr_t) regs;

    memcpy(cmds, i8042_cmds, sizeof(i8042_cmds));
    cmds[0].addr = (void *) &(((i8042_regs_t *) regs)->status);
    cmds[3].addr = (void *) &(((i8042_regs_t *) regs)->data);

    irq_code_t irq_code = {
        .rangecount = range_count,
        .ranges = ranges,
        .cmdcount = cmd_count,
        .cmds = cmds
    };

    rc = register_interrupt_handler(ddf_dev, irq_kbd, i8042_irq_handler,
                                    &irq_code);
    if (rc != EOK) {
        ddf_msg(LVL_ERROR, "Failed set handler for kbd: %s.",
                ddf_dev_get_name(ddf_dev));
        goto error;
    }

    rc = register_interrupt_handler(ddf_dev, irq_mouse, i8042_irq_handler,
                                    &irq_code);
    if (rc != EOK) {
        ddf_msg(LVL_ERROR, "Failed set handler for mouse: %s.",
                ddf_dev_get_name(ddf_dev));
        goto error;
    }

    /* Enable interrupts */
    async_sess_t *parent_sess = ddf_dev_parent_sess_get(ddf_dev);
    assert(parent_sess != NULL);

    const bool enabled = hw_res_enable_interrupt(parent_sess);
    if (!enabled) {
        log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to enable interrupts: %s.",
                ddf_dev_get_name(ddf_dev));
        rc = EIO;
        goto error;
    }

    /* Enable port interrupts. */
    wait_ready(dev);
    pio_write_8(&dev->regs->status, i8042_CMD_WRITE_CMDB);
    wait_ready(dev);
    pio_write_8(&dev->regs->data, i8042_KBD_IE | i8042_KBD_TRANSLATE |
                i8042_AUX_IE);

    return EOK;
error:
    if (kbd_bound)
        ddf_fun_unbind(dev->kbd_fun);
    if (aux_bound)
        ddf_fun_unbind(dev->aux_fun);
    if (dev->kbd_fun != NULL)
        ddf_fun_destroy(dev->kbd_fun);
    if (dev->aux_fun != NULL)
        ddf_fun_destroy(dev->aux_fun);

    return rc;
}