From 1bdd49f83a044ef47a3f4993aa08a651ed5af45b Mon Sep 17 00:00:00 2001
From: Federico Vaga <federico.vaga@gmail.com>
Date: Thu, 15 Mar 2012 09:52:11 +0100
Subject: [PATCH] zio_channel: added the current control for each channel

The current control used to be per-trigger (i.e., per-cset).
However, some parameters are per-channel (like the gain),
so each channel now has its own current control structure.

Also, zio-dump now shows device and trigger attributes, both standard
and
extended ones.

Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
Acked-by: Alessandro Rubini <rubini@gnudd.com>
---
 include/linux/zio-trigger.h |   2 -
 include/linux/zio.h         |   2 +-
 tools/zio-dump.c            |  35 ++++-
 triggers/zio-trig-irq.c     |  16 +--
 triggers/zio-trig-timer.c   |  10 +-
 triggers/zio-trig-user.c    |   7 -
 zio-cdev.c                  |   4 +-
 zio-sys.c                   | 277 +++++++++++++++++++++++++-----------
 8 files changed, 235 insertions(+), 118 deletions(-)

diff --git a/include/linux/zio-trigger.h b/include/linux/zio-trigger.h
index e50f26e..3701ca4 100644
--- a/include/linux/zio-trigger.h
+++ b/include/linux/zio-trigger.h
@@ -33,14 +33,12 @@ struct zio_ti {
 
 	unsigned long		flags;		/* input or output, etc */
 	struct spinlock		lock;
-	struct zio_control	*current_ctrl;	/* the active one */
 	/* This is for software stamping */
 	struct timespec		tstamp;
 	uint64_t tstamp_extra;
 
 	/* Standard and extended attributes for this object */
 	struct zio_attribute_set		zattr_set;
-	struct zio_ctrl_attr			zattr_val;
 
 	const struct zio_trigger_operations	*t_op;
 };
diff --git a/include/linux/zio.h b/include/linux/zio.h
index 9756146..d73ea89 100644
--- a/include/linux/zio.h
+++ b/include/linux/zio.h
@@ -158,7 +158,6 @@ struct zio_channel {
 	unsigned int		index;		/* index within parent */
 	unsigned long		flags;
 	struct zio_attribute_set zattr_set;
-	struct zio_ctrl_attr	 zattr_val;
 
 	struct device		*ctrl_dev;	/* control char device */
 	struct device		*data_dev;	/* data char device */
@@ -166,6 +165,7 @@ struct zio_channel {
 	void			*priv_d;	/* private for the device */
 	void			*priv_t;	/* private for the trigger */
 
+	struct zio_control	*current_ctrl;	/* the active one */
 	struct zio_block	*user_block;	/* being transferred w/ user */
 	struct zio_block	*active_block;	/* being managed by hardware */
 };
diff --git a/tools/zio-dump.c b/tools/zio-dump.c
index fd3fb5a..591d4bf 100644
--- a/tools/zio-dump.c
+++ b/tools/zio-dump.c
@@ -35,7 +35,7 @@ void read_channel(int cfd, int dfd, FILE *log)
 			prgname);
 		exit(1);
 	default:
-		fprintf(stderr, "%s: ctrl read: %i bytes (expected %i)\n",
+		fprintf(stderr, "%s: ctrl read: %i bytes (expected %li)\n",
 			prgname, i, sizeof(ctrl));
 		/* continue anyways */
 	case sizeof(ctrl):
@@ -82,6 +82,39 @@ void read_channel(int cfd, int dfd, FILE *log)
 	       (long long)ctrl.tstamp.secs,
 	       (long long)ctrl.tstamp.ticks,
 	       (long long)ctrl.tstamp.bins);
+	/* Print attributes */
+	printf("Device attributes:\n");
+	printf("    Standard: 0x%04x\n    ",
+	       ctrl.attr_channel.std_mask);
+	for (i = 0; i < 16; ++i) {
+		if (i == 8)
+			printf("\n    ");
+		printf ("0x%x ", ctrl.attr_channel.std_val[i]);
+	}
+	printf("\n    Extened: 0x%08x\n    ",
+	       ctrl.attr_channel.ext_mask);
+	for (i = 0; i < 32; ++i) {
+		if (i == 8 || i == 16 || i == 24)
+			printf("\n    ");
+		printf ("0x%x ", ctrl.attr_channel.ext_val[i]);
+	}
+	printf("\nTrigger attributes:\n");
+	printf("    Standard: 0x%04x\n    ",
+	       ctrl.attr_trigger.std_mask);
+	for (i = 0; i < 16; ++i) {
+		if (i == 8)
+			printf("\n    ");
+		printf ("0x%x ", ctrl.attr_trigger.std_val[i]);
+	}
+	printf("\n    Extened: 0x%08x \n    ",
+	       ctrl.attr_trigger.ext_mask);
+	for (i = 0; i < 32; ++i) {
+		if (i == 8 || i == 16 || i == 24)
+			printf("\n    ");
+		printf ("0x%x ", ctrl.attr_trigger.ext_val[i]);
+	}
+	printf("\n");
+
 	/* FIXME: some control information is missing */
 
 	i = read(dfd, buf, sizeof(buf));
diff --git a/triggers/zio-trig-irq.c b/triggers/zio-trig-irq.c
index b3110cd..e26d027 100644
--- a/triggers/zio-trig-irq.c
+++ b/triggers/zio-trig-irq.c
@@ -40,19 +40,9 @@ static struct zio_attribute zti_ext_attr[] = {
 static int zti_conf_set(struct kobject *kobj, struct zio_attribute *zattr,
 		uint32_t  usr_val)
 {
-	struct zio_ti *ti = to_zio_ti(kobj);
-
 	pr_debug("%s:%d\n", __func__, __LINE__);
 	zattr->value = usr_val;
-	switch (zattr->priv.addr) {
-	case ZTI_ATTR_NSAMPLES:
-		ti->current_ctrl->nsamples = usr_val;
-		break;
-	/* other attributes are read-only */
-	default:
-		pr_err("%s: unknown \"addr\" for configuration\n", __func__);
-		return -EINVAL;
-	}
+
 	return 0;
 }
 
@@ -106,10 +96,6 @@ static struct zio_ti *zti_create(struct zio_trigger_type *trig,
 	if (!ti)
 		return ERR_PTR(-ENOMEM);
 
-	/* The current control is already filled: just set nsamples */
-	ctrl->nsamples = zti_std_attr[ZATTR_TRIG_NSAMPLES].value;
-	ti->current_ctrl = ctrl;
-
 	ret = request_irq(zti_irq, zti_handler, IRQF_SHARED
 			  | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
 			  KBUILD_MODNAME, ti);
diff --git a/triggers/zio-trig-timer.c b/triggers/zio-trig-timer.c
index df9a741..b494351 100644
--- a/triggers/zio-trig-timer.c
+++ b/triggers/zio-trig-timer.c
@@ -50,13 +50,13 @@ static int ztt_conf_set(struct kobject *kobj, struct zio_attribute *zattr,
 	pr_debug("%s:%d\n", __func__, __LINE__);
 	zattr->value = usr_val;
 	switch (zattr->priv.addr) {
-	case ZTT_ATTR_NSAMPLES:
-		ti->current_ctrl->nsamples = usr_val;
-		break;
 	case ZTT_ATTR_PERIOD:
 		ztt = to_ztt_instance(ti);
 		ztt->period = msecs_to_jiffies(usr_val);
 		break;
+	case ZTT_ATTR_NSAMPLES:
+		/* Nothing to do */
+		break;
 	default:
 		pr_err("%s: unknown \"addr\" 0x%lx for configuration\n",
 				__func__, zattr->priv.addr);
@@ -131,10 +131,6 @@ static struct zio_ti *ztt_create(struct zio_trigger_type *trig,
 		return ERR_PTR(-ENOMEM);
 	ti = &ztt_instance->ti;
 
-	/* The current control is already filled: just set nsamples */
-	ctrl->nsamples = ztt_std_attr[ZATTR_TRIG_NSAMPLES].value;
-	ti->current_ctrl = ctrl;
-
 	/* Fill own fields */
 	setup_timer(&ztt_instance->timer, ztt_fn,
 		    (unsigned long)(&ztt_instance->ti));
diff --git a/triggers/zio-trig-user.c b/triggers/zio-trig-user.c
index b24b433..f744a8f 100644
--- a/triggers/zio-trig-user.c
+++ b/triggers/zio-trig-user.c
@@ -27,11 +27,8 @@ static DEFINE_ZATTR_STD(TRIG, ztu_std_attr) = {
 int ztu_conf_set(struct kobject *kobj, struct zio_attribute *zattr,
 		uint32_t  usr_val)
 {
-	struct zio_ti *ti = to_zio_ti(kobj);
-
 	pr_debug("%s:%d\n", __func__, __LINE__);
 	zattr->value = usr_val;
-	ti->current_ctrl->nsamples = usr_val; /* We have this one only */
 	return 0;
 }
 
@@ -65,7 +62,6 @@ static int ztu_config(struct zio_ti *ti, struct zio_control *ctrl)
 {
 	pr_debug("%s:%d\n", __func__, __LINE__);
 
-	ti->current_ctrl->nsamples = ctrl->nsamples;
 	return 0;
 }
 
@@ -80,9 +76,6 @@ static struct zio_ti *ztu_create(struct zio_trigger_type *trig,
 	ti = kzalloc(sizeof(*ti), GFP_KERNEL);
 	if (!ti)
 		return ERR_PTR(-ENOMEM);
-	/* The current control is already filled: just set nsamples */
-	ctrl->nsamples = ztu_std_attr[ZATTR_TRIG_NSAMPLES].value;
-	ti->current_ctrl = ctrl;
 
 	return ti;
 }
diff --git a/zio-cdev.c b/zio-cdev.c
index f80ee83..02e8ed5 100644
--- a/zio-cdev.c
+++ b/zio-cdev.c
@@ -338,7 +338,7 @@ static struct zio_block *__zio_write_allocblock(struct zio_bi *bi,
 		ctrl = zio_alloc_control(GFP_KERNEL);
 		if (!ctrl)
 			return NULL;
-		memcpy(ctrl, bi->cset->ti->current_ctrl, ZIO_CONTROL_SIZE);
+		memcpy(ctrl, bi->chan->current_ctrl, ZIO_CONTROL_SIZE);
 	}
 	datalen = ctrl->ssize * ctrl->nsamples;
 	block = bi->b_op->alloc_block(bi, ctrl, datalen, GFP_KERNEL);
@@ -482,7 +482,7 @@ static ssize_t zio_generic_write(struct file *f, const char __user *ubuf,
 
 	if (copy_from_user(ctrl, ubuf, count))
 		return -EFAULT;
-	memcpy(bi->cset->ti->current_ctrl, ctrl, count);
+	memcpy(chan->current_ctrl, ctrl, count);
 	*offp += count;
 	return count;
 }
diff --git a/zio-sys.c b/zio-sys.c
index 447a271..1c03afd 100644
--- a/zio-sys.c
+++ b/zio-sys.c
@@ -56,6 +56,8 @@ static void __ti_destroy(struct zio_trigger_type *trig, struct zio_ti *ti);
 static int __ti_register(struct zio_trigger_type *trig, struct zio_cset *cset,
 			 struct zio_ti *ti, const char *name);
 static void __ti_unregister(struct zio_trigger_type *trig, struct zio_ti *ti);
+/* Attributes initlialization */
+static void __zattr_trig_init_ctrl(struct zio_ti *ti, struct zio_control *ctrl);
 
 /*
  * Top-level ZIO objects has a unique name.
@@ -186,8 +188,17 @@ static void __zio_fire_input_trigger(struct zio_ti *ti)
 				pr_err("%s: can't alloc control\n", __func__);
 			continue;
 		}
-		memcpy(ctrl, ti->current_ctrl, ZIO_CONTROL_SIZE);
-		ctrl->chan_i = chan->index;
+		/*
+		 * Update sequence number too (first returned seq is 1).
+		 * Sequence number is always increased to identify un-stored
+		 * blocks or other errors in trigger activation.
+		 */
+		chan->current_ctrl->seq_num++;
+		/* Copy the stamp (we are software driven anyways) */
+		chan->current_ctrl->tstamp.secs = ti->tstamp.tv_sec;
+		chan->current_ctrl->tstamp.ticks = ti->tstamp.tv_nsec;
+		chan->current_ctrl->tstamp.bins = ti->tstamp_extra;
+		memcpy(ctrl, chan->current_ctrl, ZIO_CONTROL_SIZE);
 
 		block = zbuf->b_op->alloc_block(chan->bi, ctrl,
 						ctrl->ssize * ctrl->nsamples,
@@ -237,16 +248,6 @@ void zio_fire_trigger(struct zio_ti *ti)
 	spin_lock(&ti->cset->lock);
 	ti->flags |= ZTI_BUSY;
 	spin_unlock(&ti->cset->lock);
-	/* Copy the stamp (we are software driven anyways) */
-	ti->current_ctrl->tstamp.secs = ti->tstamp.tv_sec;
-	ti->current_ctrl->tstamp.ticks = ti->tstamp.tv_nsec;
-	ti->current_ctrl->tstamp.bins = ti->tstamp_extra;
-	/*
-	 * And the sequence number too (first returned seq is 1).
-	 * Sequence number is always increased to identify un-stored
-	 * blocks or other errors in trigger activation.
-	 */
-	ti->current_ctrl->seq_num++;
 
 	if (likely((ti->flags & ZIO_DIR) == ZIO_DIR_INPUT))
 		__zio_fire_input_trigger(ti);
@@ -481,8 +482,9 @@ static unsigned long *__get_flag(struct zio_obj_head *head)
 static int zio_change_current_trigger(struct zio_cset *cset, char *name)
 {
 	struct zio_trigger_type *trig, *trig_old = cset->trig;
+	struct zio_channel *chan;
 	struct zio_ti *ti, *ti_old = cset->ti;
-	int err;
+	int err, i;
 
 	pr_debug("%s\n", __func__);
 	spin_lock(&cset->lock);
@@ -525,6 +527,11 @@ static int zio_change_current_trigger(struct zio_cset *cset, char *name)
 	if (err)
 		WARN(1, "%s: cannot rename trigger folder for"
 			" cset%d\n", __func__, cset->index);
+	/* Update channel current controls */
+	for (i = 0; i < cset->n_chan; ++i) {
+		chan = &cset->chan[i];
+		__zattr_trig_init_ctrl(ti, chan->current_ctrl);
+	}
 	return 0;
 
 out_reg:
@@ -603,72 +610,170 @@ out:
 	return err;
 }
 
+/*
+ * used to init and update sysfs attribute value into a control.
+ * The bit mask is set also during update to make the code simple, but
+ * this does not decrease performance
+ */
 static inline void __zattr_valcpy(struct zio_ctrl_attr *ctrl,
-				  enum zattr_flags flags,
-				  int index, uint32_t value)
+				  struct zio_attribute *zattr)
 {
 	pr_debug("%s\n", __func__);
-	if ((flags & ZATTR_TYPE) == ZATTR_TYPE_EXT)
-		ctrl->ext_val[index] = value;
-	else
-		ctrl->std_val[index] = value;
+	if ((zattr->flags & ZATTR_TYPE) == ZATTR_TYPE_EXT) {
+		ctrl->ext_mask |= (1 << zattr->index);
+		ctrl->ext_val[zattr->index] = zattr->value;
+	} else {
+		if (zattr->index == ZATTR_INDEX_NONE)
+			return;
+		ctrl->std_mask |= (1 << zattr->index);
+		ctrl->std_val[zattr->index] = zattr->value;
+	}
 }
 static void __zattr_propagate_value(struct zio_obj_head *head,
 			       struct zio_attribute *zattr)
 {
-	int i, j, index, value, flags;
+	int i, j;
 	struct zio_ti *ti;
 	struct zio_device *zdev;
-	struct zio_cset *cset;
 	struct zio_channel *chan;
+	struct zio_cset *cset;
+	struct zio_control *ctrl;
 
 	pr_debug("%s\n", __func__);
-	index = zattr->index;
-	value = zattr->value;
-	flags = zattr->flags;
 	switch (head->zobj_type) {
 	case ZDEV:
 		zdev = to_zio_dev(&head->kobj);
 		for (i = 0; i < zdev->n_cset; ++i) {
 			cset = &zdev->cset[i];
-			for (j = 0; j < cset->n_chan; ++j)
-				__zattr_valcpy(&cset->chan[j].zattr_val,
-						   flags, index, value);
+			for (j = 0; j < cset->n_chan; ++j) {
+				ctrl = cset->chan[j].current_ctrl;
+				__zattr_valcpy(&ctrl->attr_channel, zattr);
+			}
 		}
 		break;
 	case ZCSET:
 		cset = to_zio_cset(&head->kobj);
-		for (i = 0; i < cset->n_chan; ++i)
-			__zattr_valcpy(&cset->chan[i].zattr_val,
-					   flags, index, value);
+		for (i = 0; i < cset->n_chan; ++i) {
+			ctrl = cset->chan[i].current_ctrl;
+			__zattr_valcpy(&ctrl->attr_channel, zattr);
+		}
 		break;
 	case ZCHAN:
-		chan = to_zio_chan(&head->kobj);
-		__zattr_valcpy(&chan->zattr_val, flags, index, value);
+		ctrl = to_zio_chan(&head->kobj)->current_ctrl;
+		__zattr_valcpy(&ctrl->attr_channel, zattr);
 		break;
 	case ZTI:
 		ti = to_zio_ti(&head->kobj);
-		__zattr_valcpy(&ti->zattr_val, flags, index, value);
+		/* Update all channel current control */
+		for (i = 0; i < ti->cset->n_chan; ++i) {
+			chan = &ti->cset->chan[i];
+			ctrl = chan->current_ctrl;
+			__zattr_valcpy(&ctrl->attr_trigger, zattr);
+			if (zattr->index == ZATTR_TRIG_NSAMPLES &&
+				(zattr->flags & ZATTR_TYPE) == ZATTR_TYPE_STD)
+				chan->current_ctrl->nsamples = zattr->value;
+		}
+
 		break;
 	default:
 		return;
 	}
 }
 
-static void __zattr_init_ctrl(struct zio_obj_head *head,
-			      struct zio_attribute_set *zattr_set)
+static void __zattr_trig_init_ctrl(struct zio_ti *ti, struct zio_control *ctrl)
 {
 	int i;
+	struct zio_ctrl_attr *ctrl_attr_trig = &ctrl->attr_trigger;
+
+	strncpy(ctrl->triggername, ti->cset->trig->head.name, ZIO_NAME_LEN);
+	/* Copy trigger value */
+	for (i = 0; i < ti->zattr_set.n_std_attr; ++i)
+		__zattr_valcpy(ctrl_attr_trig, &ti->zattr_set.std_zattr[i]);
+	for (i = 0; i < ti->zattr_set.n_ext_attr; ++i)
+		__zattr_valcpy(ctrl_attr_trig, &ti->zattr_set.ext_zattr[i]);
+}
+static int __zattr_chan_init_ctrl(struct zio_channel *chan, unsigned int start)
+{
+	struct zio_ctrl_attr*ctrl_attr_chan;
+	struct zio_control *ctrl;
+	struct zio_device *zdev;
+	struct zio_cset *cset;
+	int i;
 
-	pr_debug("%s\n", __func__);
-	/* copy standard attribute default value */
-	for (i = 0; i < zattr_set->n_std_attr; ++i)
-		__zattr_propagate_value(head, &zattr_set->std_zattr[i]);
-	/* copy extended attribute default value */
-	for (i = 0; i < zattr_set->n_ext_attr; ++i)
-		__zattr_propagate_value(head, &zattr_set->ext_zattr[i]);
+	cset = chan->cset;
+	zdev = cset->zdev;
+	ctrl = chan->current_ctrl;
+	ctrl_attr_chan = &chan->current_ctrl->attr_channel;
+	if (!(start + chan->zattr_set.n_ext_attr < 32)) {
+		pr_err("%s: too many extended attribute in %s",
+			__func__, chan->cset->zdev->head.name);
+		return -EINVAL;
+	}
+
+	pr_debug("%s copy device values\n", __func__);
+	/* Copy channel attributes */
+	for (i = 0; i < chan->zattr_set.n_std_attr; ++i)
+		__zattr_valcpy(ctrl_attr_chan, &chan->zattr_set.std_zattr[i]);
+	for (i = 0; i < chan->zattr_set.n_ext_attr; ++i) {
+		/* Fix channel extended attribute index */
+		chan->zattr_set.ext_zattr[i].index = start + i;
+		__zattr_valcpy(ctrl_attr_chan, &chan->zattr_set.ext_zattr[i]);
+	}
+
+	/* Copy cset attributes */
+	for (i = 0; i < cset->zattr_set.n_std_attr; ++i)
+		__zattr_valcpy(ctrl_attr_chan, &cset->zattr_set.std_zattr[i]);
+	for (i = 0; i < cset->zattr_set.n_ext_attr; ++i)
+		__zattr_valcpy(ctrl_attr_chan, &cset->zattr_set.ext_zattr[i]);
+
+	/* Copy device attributes */
+	for (i = 0; i < zdev->zattr_set.n_std_attr; ++i)
+		__zattr_valcpy(ctrl_attr_chan, &zdev->zattr_set.std_zattr[i]);
+	for (i = 0; i < zdev->zattr_set.n_ext_attr; ++i)
+		__zattr_valcpy(ctrl_attr_chan, &zdev->zattr_set.ext_zattr[i]);
+
+	pr_debug("%s copy trigger values\n", __func__);
+	__zattr_trig_init_ctrl(cset->ti, chan->current_ctrl);
+
+	return 0;
+}
+static int __zattr_cset_init_ctrl(struct zio_cset *cset, unsigned int start)
+{
+	int i, err, start_c;
+
+	/* Fix cset extended attribute index */
+	for (i = 0; i < cset->zattr_set.n_ext_attr; ++i)
+		cset->zattr_set.ext_zattr[i].index = start + i;
+	start_c = start + i;
+	for (i = 0; i < cset->n_chan; ++i) {
+		err = __zattr_chan_init_ctrl(&cset->chan[i], start_c);
+		if (err)
+			return err;
+	}
+	return 0;
 }
+/*
+ * fix the zio attribute index for the extended attribute within device
+ * and set the attribute value into the current control of each channel
+ */
+static int __zattr_dev_init_ctrl(struct zio_device *zdev)
+{
+	int i, err, start;
 
+	pr_debug("%s\n", __func__);
+	/* Device level */
+	/* Fix device extended attribute index */
+	for (i = 0; i < zdev->zattr_set.n_ext_attr; ++i)
+		zdev->zattr_set.ext_zattr[i].index = i;
+
+	start = i;
+	for (i = 0; i < zdev->n_cset; ++i) {
+		err = __zattr_cset_init_ctrl(&zdev->cset[i], start);
+		if (err)
+			return err;
+	}
+	return 0;
+}
  /*
  * Zio objects all handle uint32_t values. So the show and store
  * are centralized here, and each device has its own get_info and set_conf
@@ -1005,7 +1110,7 @@ ext:
 		/* valid attribute */
 		group->attrs[attr_count++] = &zattr_set->ext_zattr[j].attr;
 		zattr_set->ext_zattr[j].s_op = s_op;
-		zattr_set->ext_zattr[j].index = j;
+		zattr_set->ext_zattr[j].index = j; /* FIXME useless for zdev*/
 		zattr_set->ext_zattr[j].flags |= ZATTR_TYPE_EXT;
 	}
 out:
@@ -1118,23 +1223,12 @@ static struct zio_ti *__ti_create_and_init(struct zio_trigger_type *trig,
 					   struct zio_cset *cset)
 {
 	int err;
-	struct zio_control *ctrl;
 	struct zio_ti *ti;
 
 	pr_debug("%s\n", __func__);
-	/* Allocate and fill current control as much as possible*/
-	ctrl = zio_alloc_control(GFP_KERNEL);
-	if (!ctrl)
-		return ERR_PTR(-ENOMEM);
-	ctrl->cset_i = cset->index;
-	strncpy(ctrl->devname, cset->zdev->head.name, ZIO_NAME_LEN);
-	strncpy(ctrl->triggername, trig->head.name, ZIO_NAME_LEN);
-	ctrl->sbits = 8; /* FIXME: retrieve from attribute */
-	ctrl->ssize = cset->ssize;
 	/* Create trigger */
-	ti = trig->t_op->create(trig, cset, ctrl, 0/*FIXME*/);
+	ti = trig->t_op->create(trig, cset, NULL, 0/*FIXME*/);
 	if (IS_ERR(ti)) {
-		zio_free_control(ctrl);
 		pr_err("ZIO %s: can't create trigger, error %ld\n",
 		       __func__, PTR_ERR(ti));
 		goto out;
@@ -1148,7 +1242,6 @@ static struct zio_ti *__ti_create_and_init(struct zio_trigger_type *trig,
 	/* Copy sysfs attribute from trigger type */
 	err = __zattr_set_copy(&ti->zattr_set, &trig->zattr_set);
 	if (err) {
-		zio_free_control(ctrl);
 		trig->t_op->destroy(ti);
 		return ERR_PTR(err);
 	}
@@ -1162,7 +1255,6 @@ static void __ti_destroy(struct zio_trigger_type *trig, struct zio_ti *ti)
 	pr_debug("%s\n", __func__);
 	trig->t_op->destroy(ti);
 	__zattr_set_free(&ti->zattr_set);
-	zio_free_control(ti->current_ctrl);
 }
 static int __ti_register(struct zio_trigger_type *trig, struct zio_cset *cset,
 			 struct zio_ti *ti, const char *name)
@@ -1213,6 +1305,7 @@ static void __ti_unregister(struct zio_trigger_type *trig, struct zio_ti *ti)
  */
 static int chan_register(struct zio_channel *chan)
 {
+	struct zio_control *ctrl;
 	struct zio_bi *bi;
 	int err;
 
@@ -1220,6 +1313,20 @@ static int chan_register(struct zio_channel *chan)
 	if (!chan)
 		return -EINVAL;
 
+	/* Allocate, initialize and assign a current control for channel */
+	ctrl = zio_alloc_control(GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+	ctrl->cset_i = chan->cset->index;
+	ctrl->chan_i = chan->index;
+	strncpy(ctrl->devname, chan->cset->zdev->head.name, ZIO_NAME_LEN);
+	ctrl->sbits = 8; /* FIXME retrieve from attributes */
+	ctrl->ssize = chan->cset->ssize;
+	/* Trigger instance is already assigned so */
+	ctrl->nsamples =
+		chan->cset->ti->zattr_set.std_zattr[ZATTR_TRIG_NSAMPLES].value;
+	chan->current_ctrl = ctrl;
+
 	chan->head.zobj_type = ZCHAN;
 	err = kobject_init_and_add(&chan->head.kobj, &zdktype,
 			&chan->cset->head.kobj, "chan%i", chan->index);
@@ -1239,8 +1346,6 @@ static int chan_register(struct zio_channel *chan)
 	err = __check_dev_zattr(&chan->cset->zdev->zattr_set, &chan->zattr_set);
 	if (err)
 		goto out_remove_sys;
-	/* copy default attribute value to ctrl */
-	__zattr_init_ctrl(&chan->head, &chan->zattr_set);
 	/* Create buffer */
 	bi = __bi_create_and_init(chan->cset->zbuf, chan);
 	if (IS_ERR(bi)) {
@@ -1278,6 +1383,8 @@ out_sysfs:
 out_add:
 	/* we must _put even if it returned error */
 	kobject_put(&chan->head.kobj);
+out:
+	zio_free_control(ctrl);
 	return err;
 }
 
@@ -1294,6 +1401,7 @@ static void chan_unregister(struct zio_channel *chan)
 	zattr_set_remove(&chan->head);
 	kobject_del(&chan->head.kobj);
 	kobject_put(&chan->head.kobj);
+	zio_free_control(chan->current_ctrl);
 }
 
 /*
@@ -1415,18 +1523,6 @@ static int cset_register(struct zio_cset *cset)
 		}
 		cset->zbuf = zbuf;
 	}
-
-	/* Register all child channels */
-	for (i = 0; i < cset->n_chan; i++) {
-		cset->chan[i].index = i;
-		cset->chan[i].cset = cset;
-		cset->chan[i].flags |= cset->flags & ZIO_DIR;
-		err = chan_register(&cset->chan[i]);
-		if (err)
-			goto out_reg;
-	}
-	/* copy default attribute value to ctrl */
-	__zattr_init_ctrl(&cset->head, &cset->zattr_set);
 	/*
 	 * If no name was assigned, ZIO assigns it.  cset name is
 	 * set to the kobject name. kobject name has no length limit,
@@ -1467,28 +1563,40 @@ static int cset_register(struct zio_cset *cset)
 		cset->trig = trig;
 		cset->ti = ti;
 	}
-	spin_lock(&zstat->lock);
-	list_add(&cset->list_cset, &zstat->list_cset);
-	spin_unlock(&zstat->lock);
+
+	/* Register all child channels */
+	for (i = 0; i < cset->n_chan; i++) {
+		cset->chan[i].index = i;
+		cset->chan[i].cset = cset;
+		cset->chan[i].flags |= cset->flags & ZIO_DIR;
+		err = chan_register(&cset->chan[i]);
+		if (err)
+			goto out_reg;
+	}
 	/* Private initialization function */
 	if (cset->init) {
 		err = cset->init(cset);
 		if (err)
-			goto out_init;
+			goto out_reg;
 	}
+
+	spin_lock(&zstat->lock);
+	list_add(&cset->list_cset, &zstat->list_cset);
+	spin_unlock(&zstat->lock);
+
 	return 0;
 
-out_init:
-	cset->trig = NULL;
+out_reg:
+	for (j = i-1; j >= 0; j--)
+		chan_unregister(&cset->chan[j]);
 	__ti_unregister(trig, ti);
 out_tr:
 	__ti_destroy(trig, ti);
 out_trig:
 	zio_trigger_put(cset->trig);
-out_reg:
-	for (j = i-1; j >= 0; j--)
-		chan_unregister(&cset->chan[j]);
+	cset->trig = NULL;
 	zio_buffer_put(cset->zbuf);
+	cset->zbuf = NULL;
 out_buf:
 	cset_free_chan(cset);
 out_remove_sys:
@@ -1633,7 +1741,7 @@ int zio_register_dev(struct zio_device *zdev, const char *name)
 	err = zattr_set_create(&zdev->head, zdev->s_op);
 	if (err)
 		goto out_sysfs;
-
+	pr_debug("%s:%d\n", __func__, __LINE__);
 	/* Register all child channel sets */
 	for (i = 0; i < zdev->n_cset; i++) {
 		zdev->cset[i].index = i;
@@ -1642,8 +1750,11 @@ int zio_register_dev(struct zio_device *zdev, const char *name)
 		if (err)
 			goto out_cset;
 	}
-	/* copy default attribute value to ctrl */
-	__zattr_init_ctrl(&zdev->head, &zdev->zattr_set);
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	/* Fix extended attribute index */
+	err = __zattr_dev_init_ctrl(zdev);
+	if (err)
+		goto out_cset;
 	return 0;
 
 out_cset:
-- 
GitLab