void xencons_handle_input(void *unused) { struct xencons_interface *intf; XENCONS_RING_IDX cons, prod; CN_LOCK(cn_mtx); intf = xencons_interface(); cons = intf->in_cons; prod = intf->in_prod; CN_UNLOCK(cn_mtx); /* XXX needs locking */ while (cons != prod) { xencons_rx(intf->in + MASK_XENCONS_IDX(cons, intf->in), 1); cons++; } mb(); intf->in_cons = cons; CN_LOCK(cn_mtx); notify_remote_via_evtchn(xen_start_info->console_evtchn); xencons_tx(); CN_UNLOCK(cn_mtx); }
void xencons_rx(char *buf, unsigned len) { int i; struct tty *tp = xccons; if (xen_console_up #ifdef DDB && !kdb_active #endif ) { tty_lock(tp); for (i = 0; i < len; i++) { #ifdef KDB kdb_alt_break(buf[i], &xc_altbrk); #endif ttydisc_rint(tp, buf[i], 0); } ttydisc_rint_done(tp); tty_unlock(tp); } else { CN_LOCK(cn_mtx); for (i = 0; i < len; i++) rbuf[RBUF_MASK(rp++)] = buf[i]; CN_UNLOCK(cn_mtx); } }
static int xc_cngetc(struct consdev *dev) { int ret; if (xencons_has_input()) xencons_handle_input(NULL); CN_LOCK(cn_mtx); if ((rp - rc) && !xc_mute) { /* we need to return only one char */ ret = (int)rbuf[RBUF_MASK(rc)]; rc++; } else ret = -1; CN_UNLOCK(cn_mtx); return(ret); }
static void __xencons_tx_flush(void) { int sz; CN_LOCK(cn_mtx); while (wc != wp) { int sent; sz = wp - wc; if (sz > (WBUF_SIZE - WBUF_MASK(wc))) sz = WBUF_SIZE - WBUF_MASK(wc); if (xen_initial_domain()) { HYPERVISOR_console_io(CONSOLEIO_write, sz, &wbuf[WBUF_MASK(wc)]); wc += sz; } else { sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz); if (sent == 0) break; wc += sent; } } CN_UNLOCK(cn_mtx); }
int xencons_ring_send(const char *data, unsigned len) { struct xencons_interface *intf; XENCONS_RING_IDX cons, prod; int sent; struct evtchn_send send = { .port = HYPERVISOR_start_info->console_evtchn }; intf = xencons_interface(); cons = intf->out_cons; prod = intf->out_prod; sent = 0; mb(); KASSERT((prod - cons) <= sizeof(intf->out), ("console send ring inconsistent")); while ((sent < len) && ((prod - cons) < sizeof(intf->out))) intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++]; wmb(); intf->out_prod = prod; if (cnsl_evt_reg) xen_intr_signal(console_handle); else HYPERVISOR_event_channel_op(EVTCHNOP_send, &send); return sent; } static xencons_receiver_func *xencons_receiver; void xencons_handle_input(void *unused) { struct xencons_interface *intf; XENCONS_RING_IDX cons, prod; CN_LOCK(cn_mtx); if (xen_initial_domain()) { static char rbuf[DOM0_BUFFER_SIZE]; int l; while ((l = HYPERVISOR_console_io(CONSOLEIO_read, DOM0_BUFFER_SIZE, rbuf)) > 0) xencons_rx(rbuf, l); CN_UNLOCK(cn_mtx); return; } intf = xencons_interface(); cons = intf->in_cons; prod = intf->in_prod; CN_UNLOCK(cn_mtx); /* XXX needs locking */ while (cons != prod) { xencons_rx(intf->in + MASK_XENCONS_IDX(cons, intf->in), 1); cons++; } mb(); intf->in_cons = cons; CN_LOCK(cn_mtx); xen_intr_signal(console_handle); xencons_tx(); CN_UNLOCK(cn_mtx); } void xencons_ring_register_receiver(xencons_receiver_func *f) { xencons_receiver = f; } int xencons_ring_init(void) { int err; if (HYPERVISOR_start_info->console_evtchn == 0) return 0; err = xen_intr_bind_local_port(xencons_dev, HYPERVISOR_start_info->console_evtchn, NULL, xencons_handle_input, NULL, INTR_TYPE_MISC | INTR_MPSAFE, &console_handle); if (err) { return err; } return 0; }