static int cuda_init(void) { if (sysinfo_get_value("cuda.address.physical", &(instance->cuda_physical)) != EOK) return -1; void *vaddr; if (pio_enable((void *) instance->cuda_physical, sizeof(cuda_t), &vaddr) != 0) return -1; dev = vaddr; instance->cuda = dev; instance->xstate = cx_listen; instance->bidx = 0; instance->snd_bytes = 0; fibril_mutex_initialize(&instance->dev_lock); /* Disable all interrupts from CUDA. */ pio_write_8(&dev->ier, IER_CLR | ALL_INT); cuda_irq_code.ranges[0].base = (uintptr_t) instance->cuda_physical; cuda_irq_code.cmds[0].addr = (void *) &((cuda_t *) instance->cuda_physical)->ifr; async_set_interrupt_received(cuda_irq_handler); irq_register(10, device_assign_devno(), 0, &cuda_irq_code); /* Enable SR interrupt. */ pio_write_8(&dev->ier, TIP | TREQ); pio_write_8(&dev->ier, IER_SET | SR_INT); /* Enable ADB autopolling. */ cuda_autopoll_set(true); return 0; }
static inline void set_timer(UINT32 hz) { UINT32 div = CLK_CONST / hz; pio_write_8(CLK_PORT4, PIT_SET); pio_write_8(CLK_PORT1, div & PIT_MASK); pio_write_8(CLK_PORT1, (div >> 8) & PIT_MASK); }
void arch_irq_eoi(UINT16 irqmask) { if (irqmask & 0xff00) { pio_write_8(PIC_PIC1PORT1, 0x20); } pio_write_8(PIC_PIC0PORT1, 0x20); }
void ns16550_wire(ns16550_instance_t *instance, indev_t *input) { ASSERT(instance); ASSERT(input); instance->input = input; irq_register(&instance->irq); ns16550_clear_buffer(instance->ns16550); /* Enable interrupts */ pio_write_8(&instance->ns16550->ier, IER_ERBFI); pio_write_8(&instance->ns16550->mcr, MCR_OUT2); }
cuda_instance_t *cuda_init(cuda_t *dev, inr_t inr, cir_t cir, void *cir_arg) { cuda_instance_t *instance = malloc(sizeof(cuda_instance_t), FRAME_ATOMIC); if (instance) { instance->cuda = dev; instance->kbrdin = NULL; instance->xstate = cx_listen; instance->bidx = 0; instance->snd_bytes = 0; spinlock_initialize(&instance->dev_lock, "cuda.instance.dev_lock"); /* Disable all interrupts from CUDA. */ pio_write_8(&dev->ier, IER_CLR | ALL_INT); irq_initialize(&instance->irq); instance->irq.devno = device_assign_devno(); instance->irq.inr = inr; instance->irq.claim = cuda_claim; instance->irq.handler = cuda_irq_handler; instance->irq.instance = instance; instance->irq.cir = cir; instance->irq.cir_arg = cir_arg; instance->irq.preack = true; } return instance; }
static void cuda_irq_handler(irq_t *irq) { cuda_instance_t *instance = irq->instance; uint8_t rbuf[CUDA_RCV_BUF_SIZE]; size_t len; bool handle; handle = false; len = 0; spinlock_lock(&instance->dev_lock); /* Lower IFR.SR_INT so that CUDA can generate next int by raising it. */ pio_write_8(&instance->cuda->ifr, SR_INT); switch (instance->xstate) { case cx_listen: cuda_irq_listen(irq); break; case cx_receive: cuda_irq_receive(irq); break; case cx_rcv_end: cuda_irq_rcv_end(irq, rbuf, &len); handle = true; break; case cx_send_start: cuda_irq_send_start(irq); break; case cx_send: cuda_irq_send(irq); break; } spinlock_unlock(&instance->dev_lock); /* Handle an incoming packet. */ if (handle) cuda_packet_handle(instance, rbuf, len); }
static void cuda_irq_handler(ipc_callid_t iid, ipc_call_t *call) { uint8_t rbuf[CUDA_RCV_BUF_SIZE]; size_t len; bool handle; handle = false; len = 0; fibril_mutex_lock(&instance->dev_lock); /* Lower IFR.SR_INT so that CUDA can generate next int by raising it. */ pio_write_8(&instance->cuda->ifr, SR_INT); switch (instance->xstate) { case cx_listen: cuda_irq_listen(); break; case cx_receive: cuda_irq_receive(); break; case cx_rcv_end: cuda_irq_rcv_end(rbuf, &len); handle = true; break; case cx_send_start: cuda_irq_send_start(); break; case cx_send: cuda_irq_send(); break; } fibril_mutex_unlock(&instance->dev_lock); /* Handle an incoming packet. */ if (handle) cuda_packet_handle(rbuf, len); }
void cuda_wire(cuda_instance_t *instance, indev_t *kbrdin) { cuda_t *dev = instance->cuda; ASSERT(instance); ASSERT(kbrdin); instance->kbrdin = kbrdin; irq_register(&instance->irq); /* Enable SR interrupt. */ pio_write_8(&dev->ier, TIP | TREQ); pio_write_8(&dev->ier, IER_SET | SR_INT); /* Enable ADB autopolling. */ cuda_autopoll_set(instance, true); }
/** 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; } }
/** Write data to i8042 port. * * @param fun DDF function. * @param buffer Data source. * @param size Data size. * * @return Bytes written. * */ static int i8042_write(ddf_fun_t *fun, char *buffer, size_t size) { i8042_t *controller = dev_i8042(ddf_fun_get_dev(fun)); fibril_mutex_lock(&controller->write_guard); for (size_t i = 0; i < size; ++i) { if (controller->aux_fun == fun) { wait_ready(controller); pio_write_8(&controller->regs->status, i8042_CMD_WRITE_AUX); } wait_ready(controller); pio_write_8(&controller->regs->data, buffer[i]); } fibril_mutex_unlock(&controller->write_guard); return size; }
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 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; }
/** 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 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; }
/** 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 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)); }
/** Initialize UHCI hc hw resources. * * @param[in] instance UHCI structure to use. * For magic values see UHCI Design Guide */ void hc_init_hw(const hc_t *instance) { assert(instance); uhci_regs_t *registers = instance->registers; /* Reset everything, who knows what touched it before us */ pio_write_16(®isters->usbcmd, UHCI_CMD_GLOBAL_RESET); async_usleep(50000); /* 50ms according to USB spec(root hub reset) */ pio_write_16(®isters->usbcmd, 0); /* Reset hc, all states and counters. Hope that hw is not broken */ pio_write_16(®isters->usbcmd, UHCI_CMD_HCRESET); do { async_usleep(10); } while ((pio_read_16(®isters->usbcmd) & UHCI_CMD_HCRESET) != 0); /* Set frame to exactly 1ms */ pio_write_8(®isters->sofmod, 64); /* Set frame list pointer */ const uint32_t pa = addr_to_phys(instance->frame_list); pio_write_32(®isters->flbaseadd, pa); if (instance->hw_interrupts) { /* Enable all interrupts, but resume interrupt */ pio_write_16(&instance->registers->usbintr, UHCI_INTR_ALLOW_INTERRUPTS); } const uint16_t cmd = pio_read_16(®isters->usbcmd); if (cmd != 0) usb_log_warning("Previous command value: %x.\n", cmd); /* Start the hc with large(64B) packet FSBR */ pio_write_16(®isters->usbcmd, UHCI_CMD_RUN_STOP | UHCI_CMD_MAX_PACKET | UHCI_CMD_CONFIGURE); }
void hda_reg8_write(uint8_t *r, uint8_t val) { pio_write_8(r, val); }
/** 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; }
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); }