static void ns16550_irq_handler(irq_t *irq) { ns16550_instance_t *instance = irq->instance; ns16550_t *dev = instance->ns16550; if (pio_read_8(&dev->lsr) & LSR_DATA_READY) { uint8_t data = pio_read_8(&dev->rbr); indev_push_character(instance->input, data); } }
/** Interrupt in listen state. * * Start packet reception. */ static void cuda_irq_listen(void) { uint8_t b; b = pio_read_8(&dev->b); if ((b & TREQ) != 0) { printf("cuda_irq_listen: no TREQ?!\n"); return; } pio_read_8(&dev->sr); pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP); instance->xstate = cx_receive; }
/** Interrupt in receive state. * * Receive next byte of packet. */ static void cuda_irq_receive(void) { uint8_t b, data; data = pio_read_8(&dev->sr); if (instance->bidx < CUDA_RCV_BUF_SIZE) instance->rcv_buf[instance->bidx++] = data; b = pio_read_8(&dev->b); if ((b & TREQ) == 0) { pio_write_8(&dev->b, b ^ TACK); } else { pio_write_8(&dev->b, b | TACK | TIP); instance->xstate = cx_rcv_end; } }
/** Interrupt in listen state. * * Start packet reception. */ static void cuda_irq_listen(irq_t *irq) { cuda_instance_t *instance = irq->instance; cuda_t *dev = instance->cuda; uint8_t b; b = pio_read_8(&dev->b); if ((b & TREQ) != 0) { log(LF_OTHER, LVL_ERROR, "cuda_irq_listen: no TREQ?!"); return; } pio_read_8(&dev->sr); pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP); instance->xstate = cx_receive; }
static void cuda_send_start(void) { cuda_t *dev = instance->cuda; assert(instance->xstate == cx_listen); if (instance->snd_bytes == 0) return; /* Check for incoming data. */ if ((pio_read_8(&dev->b) & TREQ) == 0) return; pio_write_8(&dev->acr, pio_read_8(&dev->acr) | SR_OUT); pio_write_8(&dev->sr, instance->snd_buf[0]); pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP); instance->xstate = cx_send_start; }
/** Interrupt in rcv_end state. * * Terminate packet reception. Either go back to listen state or start * receiving another packet if CUDA has one for us. */ static void cuda_irq_rcv_end(void *buf, size_t *len) { uint8_t b; b = pio_read_8(&dev->b); pio_read_8(&dev->sr); if ((b & TREQ) == 0) { instance->xstate = cx_receive; pio_write_8(&dev->b, b & ~TIP); } else { instance->xstate = cx_listen; cuda_send_start(); } memcpy(buf, instance->rcv_buf, instance->bidx); *len = instance->bidx; instance->bidx = 0; }
static irq_ownership_t ns16550_claim(irq_t *irq) { ns16550_instance_t *instance = irq->instance; ns16550_t *dev = instance->ns16550; if (pio_read_8(&dev->lsr) & LSR_DATA_READY) return IRQ_ACCEPT; else return IRQ_DECLINE; }
/** Interrupt in send state. * * Send next byte or terminate transmission. */ static void cuda_irq_send(void) { if (instance->bidx < instance->snd_bytes) { /* Send next byte. */ pio_write_8(&dev->sr, instance->snd_buf[instance->bidx++]); pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK); return; } /* End transfer. */ instance->snd_bytes = 0; instance->bidx = 0; pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT); pio_read_8(&dev->sr); pio_write_8(&dev->b, pio_read_8(&dev->b) | TACK | TIP); instance->xstate = cx_listen; /* TODO: Match reply with request. */ }
/** Interrupt in send_start state. * * Process result of sending first byte (and send second on success). */ static void cuda_irq_send_start(void) { uint8_t b; b = pio_read_8(&dev->b); if ((b & TREQ) == 0) { /* Collision */ pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT); pio_read_8(&dev->sr); pio_write_8(&dev->b, pio_read_8(&dev->b) | TIP | TACK); instance->xstate = cx_listen; return; } pio_write_8(&dev->sr, instance->snd_buf[1]); pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK); instance->bidx = 2; instance->xstate = cx_send; }
static irq_ownership_t cuda_claim(irq_t *irq) { cuda_instance_t *instance = irq->instance; cuda_t *dev = instance->cuda; uint8_t ifr; spinlock_lock(&instance->dev_lock); ifr = pio_read_8(&dev->ifr); spinlock_unlock(&instance->dev_lock); if ((ifr & SR_INT) == 0) return IRQ_DECLINE; return IRQ_ACCEPT; }
static void ega_cursor_update(outdev_t *dev, sysarg_t prev_col, sysarg_t prev_row, sysarg_t col, sysarg_t row, bool visible) { /* Cursor position */ uint16_t cursor = row * ega.cols + col; pio_write_8(EGA_IO_BASE, 0x0e); pio_write_8(EGA_IO_BASE + 1, (cursor >> 8) & 0xff); pio_write_8(EGA_IO_BASE, 0x0f); pio_write_8(EGA_IO_BASE + 1, cursor & 0xff); /* Cursor visibility */ pio_write_8(EGA_IO_BASE, 0x0a); uint8_t stat = pio_read_8(EGA_IO_BASE + 1); pio_write_8(EGA_IO_BASE, 0x0a); if (visible) pio_write_8(EGA_IO_BASE + 1, stat & (~(1 << 5))); else pio_write_8(EGA_IO_BASE + 1, stat | (1 << 5)); }
static void ns16550_sendb(ns16550_t *dev, uint8_t byte) { while (!(pio_read_8(&dev->lsr) & LSR_TH_READY)) ; pio_write_8(&dev->thr, byte); }
/**< Clear input buffer. */ static void ns16550_clear_buffer(ns16550_t *dev) { while ((pio_read_8(&dev->lsr) & LSR_DATA_READY)) (void) pio_read_8(&dev->rbr); }
/** 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; }
/** Wait until it is safe to write to the device. */ static void wait_ready(i8042_t *dev) { assert(dev); while (pio_read_8(&dev->regs->status) & i8042_INPUT_FULL); }
uint8_t hda_reg8_read(uint8_t *r) { return pio_read_8(r); }