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; }
/** 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; }