diff --git a/Documentation/zio/trigger.txt b/Documentation/zio/trigger.txt
index 02c7f8182c0473e9aa9c15d95ace9f1f7ad9f07d..5417def9836bf8878698a2c2f731f3d0ede9c776 100644
--- a/Documentation/zio/trigger.txt
+++ b/Documentation/zio/trigger.txt
@@ -66,7 +66,7 @@ locally or notifying the user).
 The method asks the trigger for a new block. It may be called by
 the buffer, if it wants a block immediately. The trigger that offers
 this method (which may be NULL) is responsible for storing a block
-when available.  Since driver->input_cset completes asynchronously, this
+when available.  Since cset->raw_io completes asynchronously, this
 method can't return a block directly.  The block that will be stored
 may be shorter than what the trigger would have stored in the buffer
 by itself.
@@ -120,8 +120,7 @@ asynchronous code that runs the event will just need to call
 This function, part of zio-core, calls the internal helpers
 __zio_fire_input_trigger for input or __zio_fire_output_trigger for
 output. For input, block allocation is performed for each
-non-disabled channel, and drv->input_cset is called.
-For output, drv->outoput_cset is called.
+non-disabled channel, and cset->raw_io is called.
 
 You can refer to "zio-trig-timer" for an example of a multi-instance
 generic timer and to "zio-trig-app-request" for a non-conventional
diff --git a/doc/zio-manual.in b/doc/zio-manual.in
index 8db010f389c3e32b6d2fdb8147a26c89adab4fd2..55276edf2e295421bb81d891d12717d853e36b8a 100644
--- a/doc/zio-manual.in
+++ b/doc/zio-manual.in
@@ -891,14 +891,6 @@ are:
 	The structure includes the @code{info_get} and @code{conf_set}
         methods that act on ZIO attributes. See @ref{The Attributes}.
 
-@cindex device operations
-@item const struct zio_device_operations *d_op
-
-	The device operations are used to request input or output
-        from/to a specific cset in the device. @b{Note:} we are
-        going to remove them and have a @code{raw_io} function for
-        each cset instead.
-
 @end table
 
 We won't describe further details of @code{struct zio_device} at this point,
@@ -913,11 +905,21 @@ hierarchy because all data transfers are cset-wide. Each cset
 includes a pointer to the current trigger and buffer types.
 
 @tindex zio_cset
-The most important fields of @code{Struct zio_cset} to be filled
+The most important fields of @code{struct zio_cset} to be filled
 or used by the developer are:
 
 @table @code
 
+@cindex raw_io
+@item int (*raw_io)(struct zio_cset *cset)
+
+	This is the function that performs actual I/O or schedules it
+        to be performed when the internal trigger fires. If the
+        function returns 0, the input or output operation has already
+        been completed. A return value of @code{-EAGAIN} means that
+        cset code will call @code{trigger->data_done} at a later time.
+        Other return values are used to report real errors.
+
 @cindex sample size
 @item  unsigned ssize
 
diff --git a/drivers/zio-ad7888.c b/drivers/zio-ad7888.c
index 939595791680c02b6aad24772c73dfdde12510c2..5df190b8b958b26e5e5ea6f96b4856d4cfddb313 100644
--- a/drivers/zio-ad7888.c
+++ b/drivers/zio-ad7888.c
@@ -137,12 +137,11 @@ int ad7888_input_cset(struct zio_cset *cset)
 struct zio_sysfs_operations ad7888_s_op = {
 	.conf_set = ad7888_conf_set,
 };
-struct zio_device_operations ad7888_d_op = {
-	.input_cset = ad7888_input_cset,
-};
+
 /* channel sets available */
 static struct zio_cset ad7888_ain_cset[] = {
 	{
+		.raw_io = ad7888_input_cset,
 		.ssize = 2,
 		.n_chan = 8,
 		.flags = ZCSET_TYPE_ANALOG |	/* is analog */
@@ -152,7 +151,6 @@ static struct zio_cset ad7888_ain_cset[] = {
 struct zio_device zdev_ad7888 = {
 	.owner = THIS_MODULE,
 	.s_op = &ad7888_s_op,
-	.d_op = &ad7888_d_op,
 	.flags = 0,
 	.cset = ad7888_ain_cset,
 	.n_cset = ARRAY_SIZE(ad7888_ain_cset),
diff --git a/drivers/zio-gpio.c b/drivers/zio-gpio.c
index b7d3e8a5e0dbefec8879881cc25e1048439f4f5f..63d622ff18b9a63bdbf1120fc59ef9aae25fc33d 100644
--- a/drivers/zio-gpio.c
+++ b/drivers/zio-gpio.c
@@ -83,18 +83,15 @@ static int zgp_input(struct zio_cset *cset)
 	return 0; /* done */
 }
 
-static struct zio_device_operations zgp_d_op = {
-	.output_cset =		zgp_output,
-	.input_cset =		zgp_input,
-};
-
 static struct zio_cset zgp_cset[] = {
 	{
+		.raw_io =	zgp_output,
 		.n_chan =	1,
 		.ssize =	1,
 		.flags =	ZIO_DIR_OUTPUT | ZCSET_TYPE_ANALOG,
 	},
 	{
+		.raw_io =	zgp_input,
 		.n_chan =	1,
 		.ssize =	1,
 		.flags =	ZIO_DIR_INPUT | ZCSET_TYPE_ANALOG,
@@ -102,7 +99,6 @@ static struct zio_cset zgp_cset[] = {
 };
 static struct zio_device zgp_dev = {
 	.owner =		THIS_MODULE,
-	.d_op =			&zgp_d_op,
 	.cset =			zgp_cset,
 	.n_cset =		ARRAY_SIZE(zgp_cset),
 
diff --git a/drivers/zio-zero.c b/drivers/zio-zero.c
index d79b4f8e440efa881adfb9ec4a2ef5a5b748b444..0ee07e012105916dcd8a5e9e97fe52653c99e7a7 100644
--- a/drivers/zio-zero.c
+++ b/drivers/zio-zero.c
@@ -52,20 +52,17 @@ static int zzero_output(struct zio_cset *cset)
 	return 0; /* Already done */
 }
 
-static const struct zio_device_operations zzero_d_op = {
-	.input_cset =		zzero_input,
-	.output_cset =		zzero_output,
-};
-
 static struct zio_cset zzero_cset[] = {
 	{
 		SET_OBJECT_NAME("zero-input"),
+		.raw_io =	zzero_input,
 		.n_chan =	3,
 		.ssize =	1,
 		.flags =	ZIO_DIR_INPUT | ZCSET_TYPE_ANALOG,
 	},
 	{
 		SET_OBJECT_NAME("zero-output"),
+		.raw_io =	zzero_output,
 		.n_chan =	1,
 		.ssize =	1,
 		.flags =	ZIO_DIR_OUTPUT | ZCSET_TYPE_ANALOG,
@@ -74,7 +71,6 @@ static struct zio_cset zzero_cset[] = {
 
 static struct zio_device zzero_dev = {
 	.owner =		THIS_MODULE,
-	.d_op =			&zzero_d_op,
 	.cset =			zzero_cset,
 	.n_cset =		ARRAY_SIZE(zzero_cset),
 };
diff --git a/include/linux/zio.h b/include/linux/zio.h
index 9efe8cd0cfbcc64412b888b91f35bcb5bc454212..0663447f18d40203ccb5af5313cf01bcd105facf 100644
--- a/include/linux/zio.h
+++ b/include/linux/zio.h
@@ -87,7 +87,6 @@ struct zio_device {
 	unsigned long				flags;
 	struct zio_attribute_set		zattr_set;
 	const struct zio_sysfs_operations	*s_op;
-	const struct zio_device_operations	*d_op;
 
 	/* The full device is an array of csets */
 	struct zio_cset			*cset;
@@ -98,11 +97,6 @@ struct zio_device {
 	char *preferred_trigger;
 };
 
-struct zio_device_operations {
-	int (*input_cset)(struct zio_cset *cset);
-	int (*output_cset)(struct zio_cset *cset);
-};
-
 int __must_check zio_register_dev(struct zio_device *zdev, const char *name);
 void zio_unregister_dev(struct zio_device *zio_dev);
 
@@ -115,6 +109,7 @@ struct zio_cset {
 	struct zio_buffer_type	*zbuf;		/* buffer type for bi */
 	struct zio_trigger_type *trig;		/* trigger type for ti*/
 	struct zio_ti		*ti;		/* trigger instance */
+	int			(*raw_io)(struct zio_cset *cset);
 	spinlock_t		lock;		 /* for all I/O ops */
 
 	unsigned		ssize;		/* sample size (bytes) */
@@ -127,8 +122,8 @@ struct zio_cset {
 	struct zio_channel	*chan;
 	unsigned int		n_chan;
 
-	int (*init)(struct zio_cset *cset);
-	void (*exit)(struct zio_cset *cset);
+	int			(*init)(struct zio_cset *cset);
+	void			(*exit)(struct zio_cset *cset);
 
 	void			*priv_d;	/* private for the device */
 
diff --git a/zio-sys.c b/zio-sys.c
index 7f74cd34c93e97a2c6a5956030f900690eec0a47..4952d072a884f3d564b6722c9615c1a1eb771106 100644
--- a/zio-sys.c
+++ b/zio-sys.c
@@ -201,7 +201,7 @@ static void __zio_fire_input_trigger(struct zio_ti *ti)
 		}
 		chan->active_block = block;
 	}
-	if (!zdev->d_op->input_cset(cset)) {
+	if (!cset->raw_io(cset)) {
 		/* It succeeded immediately */
 		ti->t_op->data_done(cset);
 	}
@@ -210,12 +210,11 @@ static void __zio_fire_input_trigger(struct zio_ti *ti)
 static void __zio_fire_output_trigger(struct zio_ti *ti)
 {
 	struct zio_cset *cset = ti->cset;
-	struct zio_device *zdev = cset->zdev;
 
 	pr_debug("%s:%d\n", __func__, __LINE__);
 
 	/* We are expected to already have a block in active channels */
-	if (!zdev->d_op->output_cset(cset)) {
+	if (!cset->raw_io(cset)) {
 		/* It succeeded immediately */
 		ti->t_op->data_done(cset);
 	}
@@ -1613,10 +1612,6 @@ int zio_register_dev(struct zio_device *zdev, const char *name)
 {
 	int err = 0, i, j;
 
-	if (!zdev->d_op) {
-		pr_err("%s: new devices has no operations\n", __func__);
-		return -EINVAL;
-	}
 	if (!zdev->owner) {
 		pr_err("%s: new device has no owner\n", __func__);
 		return -EINVAL;