config root man

Current Path : /sys/dev/xen/console/

FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64
Upload File :
Current File : //sys/dev/xen/console/console.c

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: release/9.1.0/sys/dev/xen/console/console.c 235405 2012-05-13 17:04:46Z avg $");

#include <sys/param.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/consio.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/uio.h>
#include <sys/tty.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <machine/stdarg.h>
#include <machine/xen/xen-os.h>
#include <xen/hypervisor.h>
#include <xen/xen_intr.h>
#include <sys/cons.h>
#include <sys/kdb.h>
#include <sys/proc.h>

#include <dev/xen/console/xencons_ring.h>
#include <xen/interface/io/console.h>


#include "opt_ddb.h"
#ifdef DDB
#include <ddb/ddb.h>
#endif

static char driver_name[] = "xc";
devclass_t xc_devclass; /* do not make static */
static void	xcoutwakeup(struct tty *);
static void	xc_timeout(void *);
static void __xencons_tx_flush(void);
static boolean_t xcons_putc(int c);

/* switch console so that shutdown can occur gracefully */
static void xc_shutdown(void *arg, int howto);
static int xc_mute;

static void xcons_force_flush(void);
static void xencons_priv_interrupt(void *);

static cn_probe_t       xc_cnprobe;
static cn_init_t        xc_cninit;
static cn_term_t        xc_cnterm;
static cn_getc_t        xc_cngetc;
static cn_putc_t        xc_cnputc;
static cn_grab_t        xc_cngrab;
static cn_ungrab_t      xc_cnungrab;

#define XC_POLLTIME 	(hz/10)

CONSOLE_DRIVER(xc);

static int xen_console_up;
static boolean_t xc_start_needed;
static struct callout xc_callout;
struct mtx              cn_mtx;

#define RBUF_SIZE     1024
#define RBUF_MASK(_i) ((_i)&(RBUF_SIZE-1))
#define WBUF_SIZE     4096
#define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1))
static char wbuf[WBUF_SIZE];
static char rbuf[RBUF_SIZE];
static int rc, rp;
static unsigned int cnsl_evt_reg;
static unsigned int wc, wp; /* write_cons, write_prod */

#ifdef KDB
static int	xc_altbrk;
#endif

#define CDEV_MAJOR 12
#define	XCUNIT(x)	(dev2unit(x))
#define ISTTYOPEN(tp)	((tp) && ((tp)->t_state & TS_ISOPEN))
#define CN_LOCK_INIT(x, _name) \
        mtx_init(&x, _name, NULL, MTX_SPIN|MTX_RECURSE)

#define CN_LOCK(l)        								\
		do {											\
				if (panicstr == NULL)					\
                        mtx_lock_spin(&(l));			\
		} while (0)
#define CN_UNLOCK(l)        							\
		do {											\
				if (panicstr == NULL)					\
                        mtx_unlock_spin(&(l));			\
		} while (0)
#define CN_LOCK_ASSERT(x)    mtx_assert(&x, MA_OWNED)
#define CN_LOCK_DESTROY(x)   mtx_destroy(&x)


static struct tty *xccons;

static tsw_open_t	xcopen;
static tsw_close_t	xcclose;

static struct ttydevsw xc_ttydevsw = {
        .tsw_flags	= TF_NOPREFIX,
        .tsw_open	= xcopen,
        .tsw_close	= xcclose,
        .tsw_outwakeup	= xcoutwakeup,
};

static void
xc_cnprobe(struct consdev *cp)
{
	cp->cn_pri = CN_REMOTE;
	sprintf(cp->cn_name, "%s0", driver_name);
}


static void
xc_cninit(struct consdev *cp)
{ 
	CN_LOCK_INIT(cn_mtx,"XCONS LOCK");

}

static void
xc_cnterm(struct consdev *cp)
{ 
}

static void
xc_cngrab(struct consdev *cp)
{
}

static void
xc_cnungrab(struct consdev *cp)
{
}

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
xc_cnputc_domu(struct consdev *dev, int c)
{
	xcons_putc(c);
}

static void
xc_cnputc_dom0(struct consdev *dev, int c)
{
	HYPERVISOR_console_io(CONSOLEIO_write, 1, (char *)&c);
}

static void
xc_cnputc(struct consdev *dev, int c)
{

	if (xen_start_info->flags & SIF_INITDOMAIN)
		xc_cnputc_dom0(dev, c);
	else
		xc_cnputc_domu(dev, c);
}

extern int db_active;
static boolean_t
xcons_putc(int c)
{
	int force_flush = xc_mute ||
#ifdef DDB
		db_active ||
#endif
		panicstr;	/* we're not gonna recover, so force
				 * flush 
				 */

	if ((wp-wc) < (WBUF_SIZE-1)) {
		if ((wbuf[WBUF_MASK(wp++)] = c) == '\n') {
        		wbuf[WBUF_MASK(wp++)] = '\r';
#ifdef notyet
			if (force_flush)
				xcons_force_flush();
#endif
		}
	} else if (force_flush) {
#ifdef notyet
		xcons_force_flush();
#endif	    	
	}
	if (cnsl_evt_reg)
		__xencons_tx_flush();
	
	/* inform start path that we're pretty full */
	return ((wp - wc) >= WBUF_SIZE - 100) ? TRUE : FALSE;
}

static void
xc_identify(driver_t *driver, device_t parent)
{
	device_t child;
	child = BUS_ADD_CHILD(parent, 0, driver_name, 0);
	device_set_driver(child, driver);
	device_set_desc(child, "Xen Console");
}

static int
xc_probe(device_t dev)
{

	return (0);
}

static int
xc_attach(device_t dev) 
{
	int error;

	xccons = tty_alloc(&xc_ttydevsw, NULL);
	tty_makedev(xccons, NULL, "xc%r", 0);

	callout_init(&xc_callout, 0);

	xencons_ring_init();

	cnsl_evt_reg = 1;
	callout_reset(&xc_callout, XC_POLLTIME, xc_timeout, xccons);
    
	if (xen_start_info->flags & SIF_INITDOMAIN) {
			error = bind_virq_to_irqhandler(
				 VIRQ_CONSOLE,
				 0,
				 "console",
				 NULL,
				 xencons_priv_interrupt, NULL,
				 INTR_TYPE_TTY, NULL);
		
				KASSERT(error >= 0, ("can't register console interrupt"));
	}

	/* register handler to flush console on shutdown */
	if ((EVENTHANDLER_REGISTER(shutdown_post_sync, xc_shutdown,
				   NULL, SHUTDOWN_PRI_DEFAULT)) == NULL)
		printf("xencons: shutdown event registration failed!\n");
	
	return (0);
}

/*
 * return 0 for all console input, force flush all output.
 */
static void
xc_shutdown(void *arg, int howto)
{
	xc_mute = 1;
	xcons_force_flush();
}

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 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_start_info->flags & SIF_INITDOMAIN) {
			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);
}

void
xencons_tx(void)
{
	__xencons_tx_flush();
}

static void
xencons_priv_interrupt(void *arg)
{

	static char rbuf[16];
	int         l;

	while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0)
		xencons_rx(rbuf, l);

	xencons_tx();
}

static int
xcopen(struct tty *tp)
{

	xen_console_up = 1;
	return (0);
}

static void
xcclose(struct tty *tp)
{

	xen_console_up = 0;
}

static inline int 
__xencons_put_char(int ch)
{
	char _ch = (char)ch;
	if ((wp - wc) == WBUF_SIZE)
		return 0;
	wbuf[WBUF_MASK(wp++)] = _ch;
	return 1;
}


static void
xcoutwakeup(struct tty *tp)
{
	boolean_t cons_full = FALSE;
	char c;

	while (ttydisc_getc(tp, &c, 1) == 1 && !cons_full)
		cons_full = xcons_putc(c);

	if (cons_full) {
	    	/* let the timeout kick us in a bit */
	    	xc_start_needed = TRUE;
	}

}

static void
xc_timeout(void *v)
{
	struct	tty *tp;
	int 	c;

	tp = (struct tty *)v;

	tty_lock(tp);
	while ((c = xc_cngetc(NULL)) != -1)
		ttydisc_rint(tp, c, 0);

	if (xc_start_needed) {
	    	xc_start_needed = FALSE;
		xcoutwakeup(tp);
	}
	tty_unlock(tp);

	callout_reset(&xc_callout, XC_POLLTIME, xc_timeout, tp);
}

static device_method_t xc_methods[] = {
	DEVMETHOD(device_identify, xc_identify),
	DEVMETHOD(device_probe, xc_probe),
	DEVMETHOD(device_attach, xc_attach),
	{0, 0}
};

static driver_t xc_driver = {
	driver_name,
	xc_methods,
	0,
};

/*** Forcibly flush console data before dying. ***/
void 
xcons_force_flush(void)
{
	int        sz;

	if (xen_start_info->flags & SIF_INITDOMAIN)
		return;

	/* Spin until console data is flushed through to the domain controller. */
	while (wc != wp) {
		int sent = 0;
		if ((sz = wp - wc) == 0)
			continue;
		
		sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
		if (sent > 0)
			wc += sent;		
	}
}

DRIVER_MODULE(xc, nexus, xc_driver, xc_devclass, 0, 0);

Man Man