diff --git a/drivers/xen/v2v/Kconfig b/drivers/xen/v2v/Kconfig
-index 5966234..b3b6ef4 100644
+index dd48eaf..e56706d 100644
--- a/drivers/xen/v2v/Kconfig
+++ b/drivers/xen/v2v/Kconfig
@@ -22,3 +22,10 @@ config XEN_V2V_DRV
- default n
+ default n
help
Sample for Xen V2V interdomain communication services.
+
+ help
+ Xen V2V char device for userland v2v.
diff --git a/drivers/xen/v2v/Makefile b/drivers/xen/v2v/Makefile
-index f3442d9..5230cd6 100644
+index 8e35e62..c390314 100644
--- a/drivers/xen/v2v/Makefile
+++ b/drivers/xen/v2v/Makefile
-@@ -1,5 +1,6 @@
+@@ -5,4 +5,7 @@ obj-$(CONFIG_XEN_V2V_DRV) += v2vdrv.o
+ v2vdrv-objs =
+ v2vdrv-objs += v2vsamp.o v2vops.o
- obj-$(CONFIG_XEN_V2V) += v2v.o v2vutl.o
- obj-$(CONFIG_XEN_V2V_DRV) += v2vdrv.o v2vops.o
+obj-$(CONFIG_XEN_V2V_DEV) += v2vdev.o
-
++
++
ccflags-$(CONFIG_XEN_V2V_DEBUG) += -DDEBUG
diff --git a/drivers/xen/v2v/v2vdev.c b/drivers/xen/v2v/v2vdev.c
new file mode 100644
-index 0000000..c7afdf3
+index 0000000..39d0a84
--- /dev/null
+++ b/drivers/xen/v2v/v2vdev.c
-@@ -0,0 +1,400 @@
+@@ -0,0 +1,511 @@
+/******************************************************************************
+ * drivers/xen/v2v/v2vdev.c
+ *
+ * V2V broker.
-+ *
++ *
+ * Copyright (c) 2009 Jean Guyader
+ * Copyright (c) 2009 Citrix Systems, Inc.
+ *
+
+#define V2VLISTEN(len) _IOC(_IOC_WRITE, 'V', 0x01, len)
+#define V2VCONNECT(len) _IOC(_IOC_WRITE, 'V', 0x02, len)
-+#define V2VTYPE _IOC(_IOC_WRITE, 'V', 0x03, int)
+
-+#define MIN(_x_, _y_) ((_x_) > (_y_) ? (_x_) : (_y_))
++#define MIN(_x_, _y_) ((_x_) < (_y_) ? (_x_) : (_y_))
+
-+#define V2VDEV_LOG "V2V-dev"
++#define DPRINTK(fmt, args...) \
++ printk("V2V-DEV (%s:%d) "fmt, \
++ __FUNCTION__, __LINE__, ##args)
++#define IPRINTK(fmt, args...) \
++ printk(KERN_INFO "V2V-DEV: "fmt, ##args)
++#define WPRINTK(fmt, args...) \
++ printk(KERN_WARNING "V2V-DEV: "fmt, ##args)
+
+struct v2vdev_context
+{
+ int connected;
++
+ void *buff;
++ char *data_ptr;
+ size_t buff_size;
++ size_t data_len;
++
++
+ int last_err;
+ int listenner;
-+ int type;
+ struct v2v_channel *channel;
+};
+
++#if 0
++#define DUMP_CTX(a) dump_ctx(__func__, __LINE__, a)
++static void dump_ctx(const char *func, int line, struct v2vdev_context *ctx)
++{
++ printk(KERN_ERR "%s:%d conn=%d buff=%p bsize=%d dptr=%p dlen=%d err=%d\n",
++ func, line, ctx->connected,ctx->buff,ctx->buff_size,ctx->data_ptr,
++ ctx->data_len,ctx->last_err);
++}
++#endif
++#define DUMP_CTX(a) ((void)0)
++
+
+static void
+hexdump (char *prefix, void *_d, int len)
+{
+ uint8_t *d = (uint8_t *) _d;
+ int i, j, k;
-+ int s, e;
++ int e;
+
-+ printk (KERN_ERR "%s %d bytes from %p\n", prefix, len, d);
++ printk (KERN_INFO "%s %d bytes from %p\n", prefix, len, d);
+
+ if (!d || len<0)
+ return;
+
+ for (i = 0; i < e; i += 16)
+ {
-+ printk (KERN_ERR "%s %05x:", prefix, i);
++ printk ("%s %05x:", prefix, i);
+ for (j = 0; j < 16; ++j)
+ {
+ k = i + j;
+
+ if (k < len)
-+ printk (" %02x", d[k]);
++ printk ("%02x", d[k]);
+ else
-+ printk (" ");
-+ if (j == 7)
-+ printk (" ");
++ printk (" ");
+ }
+
++ printk(" ");
+ for (j = 0; j < 16; ++j)
+ {
+ k = i + j;
+ c = '.';
+ printk ("%c", c);
+ }
-+ else
-+ printk (" ");
-+ if (j == 7)
-+ printk (" ");
+ }
+ printk ("\n");
+ }
+}
+
++static int v2v_receive_in_queue(struct v2vdev_context *ctx)
++{
++ return v2v_get_wake_reason(ctx->channel, V2V_WAKE_REASON_ANY) == V2V_WAKE_REASON_RECEIVE;
++}
++
++static int v2vdev_message_get(struct v2vdev_context *ctx)
++{
++ volatile void *buff;
++ ssize_t size = 0;
++ unsigned vtype, vflags;
++
++
++ if (!ctx->connected) {
++ ctx->last_err=-ENOTCONN;
++ return ctx->last_err;
++ }
++
++ if (ctx->data_len) {
++ DPRINTK(KERN_ERR "****** data_len not zero in v2vdev_message_get\n");
++ return 0;
++ }
++
++
++ vtype = vflags = 0;
++ ctx->last_err = v2v_nc2_get_message(ctx->channel,
++ (const volatile void **)&buff, &size,
++ &vtype, &vflags);
++
++ if (ctx->last_err) {
++ if (ctx->last_err==-ENODATA)
++ ctx->last_err=0;
++ return ctx->last_err;
++ }
++
++ hexdump("<", (void *) buff, size);
++
++ if (size>ctx->buff_size) {
++ ctx->buff_size=size;
++ ctx->buff = krealloc(ctx->buff, ctx->buff_size, GFP_KERNEL);
++ }
++
++ memcpy(ctx->buff, (void *)buff, size);
++ ctx->data_len=size;
++ ctx->data_ptr=ctx->buff;
++ //if (ctx->data_len > 2) ctx->data_len -=2;
++
++
++ v2v_nc2_finish_message(ctx->channel);
++ v2v_set_wake_reason(ctx->channel, V2V_WAKE_REASON_RECEIVE);
++
++ return ctx->last_err;
++}
++
+static int v2vdev_wait_connected(struct v2vdev_context *ctx)
+{
+ struct v2v_wait *wait_state;
+ while (!ctx->connected)
+ {
+ wait_state = v2v_get_wait_state(ctx->channel);
-+ printk(V2VDEV_LOG" wait event ....\n");
++ DPRINTK("wait event ....\n");
+ wait_event(wait_state->wait_event,
+ atomic_xchg(&wait_state->wait_condition, 0) == 1);
+ v2v_get_wake_reason(ctx->channel, reasons_mask);
+ err = v2v_get_remote_state(ctx->channel, &state);
+ if (err)
+ {
-+ printk(V2VDEV_LOG" failure in v2v_get_remote_state() - err: %d\n", err);
++ DPRINTK("failure in v2v_get_remote_state() - err: %d\n", err);
++ ctx->connected = 0;;
+ v2v_disconnect(ctx->channel);
+ return err;
+ }
-+ printk(V2VDEV_LOG" endpoint state: %s\n", v2v_endpoint_state_name(state));
++ DPRINTK("endpoint state: %s\n", v2v_endpoint_state_name(state));
+ ctx->connected = state == v2v_state_connected;
+ }
+ return 0;
+ err = v2v_listen(path, &ctx->channel, 0, 0, 0);
+ if (err)
+ {
-+ printk(V2VDEV_LOG" failure in v2v_listen() - error: %d\n", err);
++ DPRINTK("failure in v2v_listen() - error: %d\n", err);
+ return err;
+ }
+ BUG_ON(ctx->channel == NULL);
+ return -EINVAL;
+ path[size] = 0;
+
-+ printk(V2VDEV_LOG" connect on %s\n", path);
++ DPRINTK("connect on %s\n", path);
+
+ err = v2v_connect(path, &ctx->channel, 0);
+ if (err)
+ {
-+ printk(V2VDEV_LOG" failure in connect() - err: %d\n", err);
++ DPRINTK("failure in connect() - err: %d\n", err);
+ return err;
+ }
+
+ err = v2vdev_wait_connected(ctx);
+ if (err)
+ {
-+ printk(V2VDEV_LOG" failure in wait_connected() - error: %d\n", err);
++ DPRINTK("failure in wait_connected() - error: %d\n", err);
+ return err;
+ }
+ return 0;
+ size_t count, loff_t *ppos)
+{
+ struct v2vdev_context *ctx = filp->private_data;
-+ ssize_t n, size;
-+ uint16_t tag;
-+
-+ if (ctx->last_err)
-+ return -ctx->last_err;
-+
-+ size = MIN(count, ctx->buff_size);
-+ n = copy_to_user(buf, ctx->buff, size);
-+ ctx->buff_size -= size;
-+ if (ctx->buff_size == 0)
-+ {
-+ kfree(ctx->buff);
-+ ctx->buff = NULL;
-+ }
-+ else
-+ ctx->buff += size;
-+
-+ v2v_nc2_finish_message(ctx->channel);
-+ v2v_set_wake_reason(ctx->channel, V2V_WAKE_REASON_RECEIVE);
-+ return size - n;
++ struct v2v_wait *wait_state;
++ size_t red=0;
++ size_t n;
++ int nonblock=filp->f_flags & O_NONBLOCK;
++ u8 reasons_mask = V2V_WAKE_REASON_CONTROL | V2V_WAKE_REASON_RECEIVE;
++ u8 reason;
++ enum v2v_endpoint_state state;
++
++ DUMP_CTX(ctx);
++ if (!ctx->connected)
++ return -ENOTCONN;
++
++ while (count) {
++
++ if (!ctx->data_len) {
++
++ if (ctx->last_err)
++ return ctx->last_err;
++
++ if (nonblock && !v2v_receive_in_queue(ctx)) {
++ DPRINTK("v2vdev_read needed got %d/%d\n",red,count+red);
++ return red ? red:-EAGAIN;
++ }
++
++ wait_state = v2v_get_wait_state(ctx->channel);
++ wait_event(wait_state->wait_event,
++ atomic_xchg(&wait_state->wait_condition, 0) == 1);
++ reason = v2v_get_wake_reason(ctx->channel, reasons_mask);
++ if (reason & V2V_WAKE_REASON_CONTROL)
++ {
++ if (v2v_get_remote_state(ctx->channel, &state) == 0 &&
++ state != v2v_state_connected)
++ {
++ ctx->connected = 0;
++ v2v_disconnect(ctx->channel);
++ return 0;
++ }
++ }
++ v2vdev_message_get(ctx);
++ }
++ DUMP_CTX(ctx);
++
++ n=MIN(count,ctx->data_len);
++
++ if (n) {
++ if (copy_to_user(buf, ctx->data_ptr, n))
++ return -EFAULT;
++ red+=n;
++ count-=n;
++ ctx->data_ptr+=n;
++ ctx->data_len-=n;
++ buf+=n;
++
++ DUMP_CTX(ctx);
++ }
++ }
++
++ DPRINTK("v2vdev_read needed got %d/%d\n",red,red);
++
++ return red;
+}
+
+static ssize_t v2vdev_write(struct file *filp, const char __user *buf,
+ struct v2vdev_context *ctx = filp->private_data;
+ volatile void *msg;
+ int err;
-+
-+ err = v2v_nc2_prep_message(ctx->channel, count, ctx->type, 0, &msg);
++
++ DUMP_CTX(ctx);
++ if (!ctx->connected)
++ return -ENOTCONN;
++
++ err = v2v_nc2_prep_message(ctx->channel, count, 1, 0, &msg);
+ if (err)
+ {
-+ printk(V2VDEV_LOG" failure in v2v_nc2_prep_message() - error: %d\n", err);
-+ return -EAGAIN;
++ DPRINTK("failure in v2v_nc2_prep_message() - error: %d\n", err);
++ return -EIO;
+ }
+
-+ if (copy_from_user((void *)msg, buf, count) != 0)
-+ {
-+ printk(V2VDEV_LOG" failure in copy_from_user()\n");
-+ return 0;
-+ }
++ if (copy_from_user((void *)msg, buf, count))
++ return -EFAULT;
+
-+ hexdump(">", msg, count);
++ hexdump(">", (void *) msg, count);
+ v2v_nc2_send_messages(ctx->channel);
+ v2v_set_wake_reason(ctx->channel, V2V_WAKE_REASON_SEND);
+ return count;
+
+static long v2vdev_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
-+{
-+ int rc;
-+ struct v2vdev_context *ctx = filp->private_data;
-+
++{
++ int rc;
++ void __user *p = (void __user *)arg;
++ struct v2vdev_context *ctx = filp->private_data;
++
+ rc = -ENOSYS;
+ switch (cmd) {
+ default:
+ if (_IOC_TYPE(cmd) != 'V')
-+ return -EINVAL;
++ return -ENOTTY;
+
+ if (_IOC_DIR(cmd) == _IOC_WRITE)
+ {
+ if ((_IOC_NR(cmd) == _IOC_NR(V2VLISTEN(0))))
-+ rc = v2vdev_listen(ctx, (void __user *)arg, _IOC_SIZE(cmd));
++ rc = v2vdev_listen(ctx, p, _IOC_SIZE(cmd));
+ if ((_IOC_NR(cmd) == _IOC_NR(V2VCONNECT(0))))
-+ rc = v2vdev_connect(ctx, (void __user *)arg, _IOC_SIZE(cmd));
-+ if ((_IOC_NR(cmd) == _IOC_NR(V2VTYPE)))
-+ ctx->type = arg;
++ rc = v2vdev_connect(ctx, p, _IOC_SIZE(cmd));
+ }
+ break;
+ }
+
+ ctx = kmalloc(sizeof (struct v2vdev_context), GFP_KERNEL);
+ memset(ctx, 0, sizeof (struct v2vdev_context));
-+ /* Set the default type to DATA_STREAM */
-+ ctx->type = 1;
+ filp->private_data = ctx;
+ return 0;
+}
+{
+ struct v2vdev_context *ctx = filp->private_data;
+
++ DPRINTK("Release device\n");
+ if (ctx->connected)
+ v2v_disconnect(ctx->channel);
+ if (ctx->buff)
+ return 0;
+}
+
-+static int v2vdev_message_get(struct v2vdev_context *ctx)
-+{
-+ volatile void *buff;
-+ ssize_t size = 0;
-+ unsigned vtype, vflags;
-+ uint16_t tag;
-+
-+ vtype = vflags = 0;
-+ ctx->last_err = v2v_nc2_get_message(ctx->channel,
-+ (const volatile void **)&buff, &size,
-+ &vtype, &vflags);
-+ if (ctx->last_err == 0)
-+ {
-+ hexdump("<", buff, size);
-+ ctx->buff = krealloc(ctx->buff, ctx->buff_size + size, GFP_KERNEL);
-+ memcpy(ctx->buff + ctx->buff_size, (void *)buff, size);
-+ ctx->buff_size += size;
-+ }
-+ return ctx->last_err;
-+}
-+
+static unsigned int v2vdev_poll(struct file *filp, poll_table *wait)
+{
+ unsigned int mask = 0;
+ struct v2v_wait *wait_state;
+ u8 reasons_mask = V2V_WAKE_REASON_CONTROL;
+ u8 reason;
-+
-+ if (!ctx->connected)
-+ reasons_mask |= V2V_WAKE_REASON_ANY;
-+ else
-+ reasons_mask |= V2V_WAKE_REASON_RECEIVE;
++ int err;
++ enum v2v_endpoint_state state;
+
+ wait_state = v2v_get_wait_state(ctx->channel);
+ poll_wait(filp, &wait_state->wait_event, wait);
+
-+ if (!ctx->connected && ctx->listenner)
-+ if (v2v_accept(ctx->channel, 1) != EAGAIN)
++ if (ctx->connected)
++ reasons_mask |= V2V_WAKE_REASON_RECEIVE;
++
++ reason = v2v_get_wake_reason(ctx->channel, reasons_mask);
++ if (reason & V2V_WAKE_REASON_CONTROL)
++ {
++ if (!ctx->connected) {
++ err = v2v_get_remote_state(ctx->channel, &state);
++ if (ctx->listenner && (err == 0 && state == v2v_state_connected) &&
++ v2v_accept(ctx->channel, 1) == 0)
++ {
++ v2vdev_wait_connected(ctx);
++ v2v_set_wake_reason(ctx->channel, V2V_WAKE_REASON_SEND);
++ DPRINTK("connected !\n");
++ return 0;
++ }
++ }
++ else
+ {
-+ v2vdev_wait_connected(ctx);
-+ printk(V2VDEV_LOG" connected !\n");
-+ return 0;
++ err = v2v_get_remote_state(ctx->channel, &state);
++ if (err == 0 && ctx->connected && state != v2v_state_connected)
++ {
++ DPRINTK("Remote end %s, v2v_disconnect\n", v2v_endpoint_state_name(state));
++ ctx->connected = 0;
++ v2v_disconnect(ctx->channel);
++ return POLLIN | POLLRDNORM;
++ }
+ }
++ }
++ else if (reason & V2V_WAKE_REASON_RECEIVE)
++ {
++ DUMP_CTX(ctx);
++ v2vdev_message_get(ctx);
++ }
++
++ if (ctx->data_len)
++ mask = POLLIN | POLLRDNORM;
++
+
-+ reason = v2v_get_wake_reason(ctx->channel, reasons_mask);
-+ if (reason & V2V_WAKE_REASON_RECEIVE)
-+ if (v2vdev_message_get(ctx) == 0)
-+ mask = POLLIN | POLLRDNORM;
+ return mask;
+}
+
+
+ err = misc_register(&v2vdev_miscdev);
+ if (err != 0) {
-+ printk(KERN_ALERT "Could not register /dev/v2v\n");
++ DPRINTK(KERN_ALERT "Could not register /dev/v2v\n");
+ return err;
+ }
-+
-+ printk("Xen V2V device installed.\n");
++
++ DPRINTK("Xen V2V device installed.\n");
+
+ return 0;
+}