linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/7] Introducing ZIO, a new I/O framework
@ 2011-11-26 17:30 Alessandro Rubini
  2011-11-26 17:30 ` [RFC PATCH 1/7] Documentation: add docs for drivers/zio Alessandro Rubini
                   ` (8 more replies)
  0 siblings, 9 replies; 25+ messages in thread
From: Alessandro Rubini @ 2011-11-26 17:30 UTC (permalink / raw)
  To: linux-iio, greg, linux-kernel
  Cc: federico.vaga, dcobas, siglesia, manohar.vanga

This RFC patch-set introduces the ZIO framework for input/output,
which will be used in the new series of drivers by the BE-CO-HT
group at CERN.

The use-case it is meant to cover is very fast I/O with
hardware-provided timestamps.  The first production driver we will
support is a 100Ms/s 4-channel 14-bit ADC (developed on ohwr: see
http://www.ohwr.org/projects/fmc-adc-100m14b4cha ).  We need similar
bandwidth on output.

The synchronization engine of that FMC card and other ones is going to
be White Rabbit (http://www.ohwr.org/projects/white-rabbit).

Currently, the patch-set includes one example driver (zio-zero)
that behaves like /dev/zero and /dev/urandom. Other drivers will
come soon, both demo and real hardware.

Slides for a tutorial on the design ideas are online here:
http://www.ohwr.org/attachments/881/zio-111123.pdf

A list of pending issues and development plans is online at:
http://www.ohwr.org/projects/zio/wiki/Todo

/alessandro

Alessandro Rubini (5):
  Documentation: add docs for drivers/zio
  include/linux: add headers for drivers/zio
  drivers/zio: add triggers and buffers
  drivers/zio: add user-space tool zio-dump
  zio: insert in Kbuild so it is actually compiled

Federico Vaga (2):
  drivers/zio: core files for the ZIO input/output framework
  drivers/zio: add the zio-zero device driver

 Documentation/zio/00-INDEX            |   10 +
 Documentation/zio/buffer.txt          |  114 +++
 Documentation/zio/device.txt          |   69 ++
 Documentation/zio/modules.txt         |   45 +
 Documentation/zio/trigger.txt         |  128 +++
 drivers/Kconfig                       |    2 +
 drivers/Makefile                      |    1 +
 drivers/zio/Kconfig                   |   12 +
 drivers/zio/Makefile                  |   10 +
 drivers/zio/README                    |  105 +++
 drivers/zio/buffers/Makefile          |    1 +
 drivers/zio/buffers/zio-buf-kmalloc.c |  273 +++++++
 drivers/zio/drivers/Makefile          |    1 +
 drivers/zio/drivers/zio-zero.c        |   87 ++
 drivers/zio/triggers/Makefile         |    2 +
 drivers/zio/triggers/zio-trig-irq.c   |  203 +++++
 drivers/zio/triggers/zio-trig-timer.c |  193 +++++
 drivers/zio/zio-cdev.c                |  498 ++++++++++++
 drivers/zio/zio-dump.c                |  196 +++++
 drivers/zio/zio-sys.c                 | 1423 +++++++++++++++++++++++++++++++++
 include/linux/zio-buffer.h            |  246 ++++++
 include/linux/zio-sysfs.h             |  122 +++
 include/linux/zio-trigger.h           |   99 +++
 include/linux/zio.h                   |  244 ++++++
 24 files changed, 4084 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/zio/00-INDEX
 create mode 100644 Documentation/zio/buffer.txt
 create mode 100644 Documentation/zio/device.txt
 create mode 100644 Documentation/zio/modules.txt
 create mode 100644 Documentation/zio/trigger.txt
 create mode 100644 drivers/zio/Kconfig
 create mode 100644 drivers/zio/Makefile
 create mode 100644 drivers/zio/README
 create mode 100644 drivers/zio/buffers/Makefile
 create mode 100644 drivers/zio/buffers/zio-buf-kmalloc.c
 create mode 100644 drivers/zio/drivers/Makefile
 create mode 100644 drivers/zio/drivers/zio-zero.c
 create mode 100644 drivers/zio/triggers/Makefile
 create mode 100644 drivers/zio/triggers/zio-trig-irq.c
 create mode 100644 drivers/zio/triggers/zio-trig-timer.c
 create mode 100644 drivers/zio/zio-cdev.c
 create mode 100644 drivers/zio/zio-dump.c
 create mode 100644 drivers/zio/zio-sys.c
 create mode 100644 include/linux/zio-buffer.h
 create mode 100644 include/linux/zio-sysfs.h
 create mode 100644 include/linux/zio-trigger.h
 create mode 100644 include/linux/zio.h

-- 
1.7.7.2

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [RFC PATCH 1/7] Documentation: add docs for drivers/zio
  2011-11-26 17:30 [RFC PATCH 0/7] Introducing ZIO, a new I/O framework Alessandro Rubini
@ 2011-11-26 17:30 ` Alessandro Rubini
  2011-11-26 20:00   ` Greg KH
                     ` (3 more replies)
  2011-11-26 17:30 ` [RFC PATCH 2/7] include/linux: add headers " Alessandro Rubini
                   ` (7 subsequent siblings)
  8 siblings, 4 replies; 25+ messages in thread
From: Alessandro Rubini @ 2011-11-26 17:30 UTC (permalink / raw)
  To: linux-iio, greg, linux-kernel
  Cc: federico.vaga, dcobas, siglesia, manohar.vanga

This is documentation for the beta3 release of zio.
The files match commit 7d37663 in git://ohwr.org/misc/zio.git .

We are aware the "modules.txt" file is not correct as it lists files
that are not ready. We decided to avoid fixing it for this RFC
submission, which won't go upstream anyways.

Signed-off-by: Alessandro Rubini <rubini@gnudd.com>
Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
Acked-by: Juan David Gonzalez Cobas <dcobas@cern.ch>
Acked-by: Samuel Iglesias Gonsalvez <siglesia@cern.ch>
Acked-by: Manohar Vanga <manohar.vanga@cern.ch>
---
 Documentation/zio/00-INDEX    |   10 +++
 Documentation/zio/buffer.txt  |  114 ++++++++++++++++++++++++++++++++++++
 Documentation/zio/device.txt  |   69 ++++++++++++++++++++++
 Documentation/zio/modules.txt |   45 ++++++++++++++
 Documentation/zio/trigger.txt |  128 +++++++++++++++++++++++++++++++++++++++++
 drivers/zio/README            |  105 +++++++++++++++++++++++++++++++++
 6 files changed, 471 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/zio/00-INDEX
 create mode 100644 Documentation/zio/buffer.txt
 create mode 100644 Documentation/zio/device.txt
 create mode 100644 Documentation/zio/modules.txt
 create mode 100644 Documentation/zio/trigger.txt
 create mode 100644 drivers/zio/README

diff --git a/Documentation/zio/00-INDEX b/Documentation/zio/00-INDEX
new file mode 100644
index 0000000..093d9fb
--- /dev/null
+++ b/Documentation/zio/00-INDEX
@@ -0,0 +1,10 @@
+00-INDEX
+	- this file
+device.txt
+	- description of what ZIO devices (and csets and channels) are.
+buffer.txt
+	- description of the buffer, it's methods and how it is used.
+trigger.txt
+	- what is a trigger and what's its role in ZIO.
+modules.txt
+	- list of modules (and description) found in the first ZIO package
diff --git a/Documentation/zio/buffer.txt b/Documentation/zio/buffer.txt
new file mode 100644
index 0000000..f80e63a
--- /dev/null
+++ b/Documentation/zio/buffer.txt
@@ -0,0 +1,114 @@
+
+ZIO defines a "buffer" object type, so each device can exploit any
+features it may offer to speed up data transfers.
+
+Each cset in a device can use a different buffer, which is specified
+as an attribute of the cset.  One instance of the buffer type exists
+for each channel, and the char devices (control and data: see
+device.txt) refer to the buffer.
+
+Please read <linux/zio-buffer.h> together with this file.
+
+	Buffer Types
+	============
+
+Buffers may be device-specific or generic. A generic buffer called
+"kmalloc" is provided within zio-core; it uses kmalloc for allocation
+data blocks.  Such buffer is activated by default on all new csets
+being registered but is not special in any other way, you can write
+your own generic buffer (and if it's better than ours, we may use it
+as default buffer in future releases).
+
+A device-specific buffer declares to be such within its attributes.  A
+device-specific buffer can only be used by csets that declare its name
+as preferred buffer type.  When such csets are registered, if the
+buffer is already known to ZIO, it will be activated by default instead
+of "kmalloc".
+
+Sometimes people write drivers for a set of similar devices, with
+similar DMA capabilities. In this case, all of them may refer to the
+same device-specific buffer type; the buffer type may be registered
+as a standalone kernel module.
+
+The ZIO buffer data structures includes two sets of operations:
+file_operations and buffer_operations.
+
+
+	Buffer Operations
+	=================
+
+Each buffer type must provide the following buffer operations. All
+of them are implemented in zio-buf-kmalloc.c, which may be used as
+reference to better understand the role of each method:
+
+	struct zio_bi *(*create)(struct zio_buffer_type *zbuf,
+				 struct zio_channel *ch,
+				 fmode_t f_flags);
+	void (*destroy)(struct zio_bi *bi);
+
+The create() operation allocates and initializes an instance of the
+buffer type. It is called by ZIO when a channel is opened for the
+first time. The operation return a zio buffer instance (zio_bi),
+which is the generic descriptor of a buffer instance. ZIO handles
+only zio_bi, so complex buffer structures must contain the zio_bi
+structure and use container_of() to access the private enclosing
+structure.
+
+Destroy() deallocates a buffer instance. ZIO calls destroy when the
+channel is unregistered from ZIO or when the user assigns a different
+buffer type to the channel.
+
+When the control/data devices are closed, ZIO doesn't call destroy, so
+incoming data can queue up while the application leaves it closed
+(e.g., a shell script).  Actually, the release file operation is not
+handled by ZIO, so it couldn't call destroy on close even if it wanted
+to.
+
+	struct zio_block *(*alloc_block)(struct zio_bi *bi,
+					 struct zio_control *ctrl,
+					 size_t datalen, gfp_t gfp);
+	void (*free_block)(struct zio_bi *bi, struct zio_block *block);
+
+For input channels, a block is allocated before the trigger fires, and
+it is freed when the user has read or explicitly ignored it. For
+output, allocation happens on user write and free is called by the
+trigger when it is done. Thus, the functions are sometimes called by
+buffer code itself, and sometimes by the trigger. The generic
+structure hosting a block is zio_block which contain both data
+(samples) and control informations.  If needed, buffers may use a more
+complex structure, which will include zio_block, which is the only
+structure that ZIO handles; by using container_of you can retrieve the
+enclosing complex structure used in your buffer
+
+	int (*store_block)(struct zio_bi *bi, struct zio_block *block);
+	struct zio_block (*retr_block) (struct zio_bi *bi);
+
+For input the trigger calls store_block() and the read system call issues
+retr_block().  For output, the write system call runs store_block()
+and the trigger may call retr_block() (although the buffer pushes to
+the trigger when it receives the first data block).
+
+
+	File Operations
+	===============
+
+This field hosts the file_operations used by the char devices (control and
+data) for every channel using this buffer type.  When char devices are
+initially opened, the open method being run is within zio-code;
+it  kmallocs f->private_data before calling the buffer-specific open
+method. The private data being used is:
+
+	struct zio_f_priv {
+		struct zio_channel *chan;
+		enum zio_cdev_type type;
+	};
+
+All buffer file operations can thus refer to the current channel (and
+its buffer and its trigger), and know if the current file is
+ZIO_CDEV_CTRL or ZIO_CDEV_DATA.  Every buffer is expected to
+call zio_generic_release() at the end of its own release operation, or
+used zio_generic_release() directly in the file operations.
+
+ZIO offers other generic file operations, that may be enough for your
+buffer code or not. See zio-buf-kmalloc.c for a working example of
+buffer file operations.
diff --git a/Documentation/zio/device.txt b/Documentation/zio/device.txt
new file mode 100644
index 0000000..0c960e2
--- /dev/null
+++ b/Documentation/zio/device.txt
@@ -0,0 +1,69 @@
+
+	ZIO Device
+	==========
+
+A device, registered through zio_register_device() is the description
+of an I/O peripheral. It is made up of channel-sets, called csets
+from now on. A device may represent a PCI board or an SPI integrated
+circuit or whatever it makes sense to manage from a single device driver.
+All I/O operations are performed on csets, so the device is just an
+array of csets.
+
+	Csets
+	=====
+
+A cset (channel-set) is an homogeneous set of I/O channels. All
+channels in the set are feature the same physical characteristics;
+moreover, a cset refers to a trigger object, so all channels in a set
+are triggered by the same event. This is the typical use case for
+logic analysers (digital input) or multi-probe scopes (analog input),
+as well as multi-waveform output. If your device has several input
+channels which are separately triggered, they should be defined as
+several cset items, each featuring one channel only.  Finally, all
+channels in a cset use the same buffer object for in-kernel data
+storage. Both the buffer and the trigger for a cset are set by
+writing the proper name in sysfs. At device registration defaults
+apply. If ZIO can't find the trigger/buffer name you wrote,
+it will return EINVAL and leave the previous trigger/buffer in place.
+
+	Channels
+	========
+
+The channel is the lowest object in the ZIO hierarchy. It represents
+the single physical connector of the device: analog or digital, input
+or output. Time-to-digital and digital-to-time devices can be represented
+as channels as well.
+
+	Attributes
+	==========
+
+Most configuration and information in ZIO happens through sysfs.
+See sysfs.txt for information about attributes. (FIXME: sysfs.txt)
+
+	Data Transfers
+	==============
+
+Data transfer in ZIO uses two char devices for each channel offered by
+the driver. One char device is used to describe data blocks (we call
+it control device); the other is used to transfer the data blocks (we
+call it data device). The control device returns (or accepts) a
+fixed-size structure that describes the next data transfer, including
+the trigger in use, data size, number of samples and various
+attributes.  Applications may choose to read the data device alone,
+without retrieving control information: when any data of a new block
+is transferred, the associated control information is discarded.
+Similarly, data is discarded if you re-read the control device after
+having retrieved the description of a data block you are not
+interested in.  For output, writing data without writing control uses
+the default control information, or the one from the previous
+transfer.
+
+The full set of rules for data and control transfers is described
+elsewhere (FIXME: link to other docs) but it is pretty intuitive once
+you get the idea.
+
+See the "zio-dump" host tool in the top-level zio dir for an example
+of generic and simple input application that shows use of control and
+data files.
+
+
diff --git a/Documentation/zio/modules.txt b/Documentation/zio/modules.txt
new file mode 100644
index 0000000..b3df00a
--- /dev/null
+++ b/Documentation/zio/modules.txt
@@ -0,0 +1,45 @@
+
+This is the list of ZIO modules, at the time of writing. It is there
+to help new users understanding how the parts stick together.
+
+  drivers/zio/zio-core.ko
+
+This module (which is linked from several source files) includes the
+core sysfs and attribute management. It exports the register and
+unregister functions for top-level objects. Moreover, it includes the
+default buffer, called "kmalloc" and default trigger, called
+"app-request".
+
+  drivers/zio/trigger/trig-ktimer.ko
+  drivers/zio/trigger/trig-hrt.ko
+  drivers/zio/trigger/trig-irq.ko
+
+Three other generic triggers. Two of them are time-based, and the
+third hooks to an external interrupt (or more than one) as source of
+trigger that can be used be any zio cset).
+
+  drivers/zio/dev/zio-null.ko
+  drivers/zio/dev/zio-parport.ko
+  drivers/zio/dev/zio-ad7888.ko
+  drivers/zio/dev/zio-uart.ko
+
+These modules are examples. "null" does nothing: it discards output
+data and returns zeroes as input data. It can be used to experiment
+with generic triggers and as a sandbox for local modifications and
+testing.
+
+The parport driver registers two output csets and two input cset.
+In each group one cset is byte-oriented and the other is bit-oriented.
+
+The ad7888 is an SPI ADC we mounted on an ARM board. It's a real
+8-channel ADC we are using for internal development, and this is a
+real driver for a real thing. Over time it will handle its own buffer
+type (our SPI master uses DMA) and its own data-driven trigger (even
+if the data will be scanned by the CPU, so it can only work at low
+data rates).
+
+The uart driver is a line discpline that can receive data from a
+serial port. The first implementation expects to receive an endless
+stream of 16-bit data, big endian (we used this to run on-board ADC on
+cortex-m3), but we plan to extend it as a serious test case. You can
+drive it from a pty slave, for example.
diff --git a/Documentation/zio/trigger.txt b/Documentation/zio/trigger.txt
new file mode 100644
index 0000000..95b426f
--- /dev/null
+++ b/Documentation/zio/trigger.txt
@@ -0,0 +1,128 @@
+
+ZIO defines a "trigger" object type, and each cset is connected to
+a trigger.
+
+Each cset in a device can use a different trigger, which is specified
+as an attribute of the cset.  When the trigger fires, it acts on all
+the non-disabled channels of the cset.  Only the "app-request" trigger
+can act on a single channel at a time.
+
+Please read <linux/zio-trigger.h> together with this file.
+
+	Trigger Types
+	=============
+
+Triggers may be device-specific or generic. A few generic triggers
+are part of zio-core. The "app-request" trigger fires input when
+the application calls read and fires output when the application calls
+write (it acts on a single channel). The "ktimer" trigger uses a kernel
+timer as trigger source. The "irq" trigger uses any interrupt (e.g.,
+a GPIO interrupt, or pin 10 of the PC parallel port) as trigger event.
+
+A device-specific trigger declares to be such within its attributes.  A
+device-specific trigger can only be used by csets that declare its name
+as preferred trigger type.  When such csets are registered, if the
+trigger is already known to ZIO, it will be activated by default instead
+of "app-request".
+
+	Trigger Operations
+	==================
+
+Trigger operations are the following:
+
+	struct zio_ti *(*create)(struct zio_trigger_type *trig,
+				 struct zio_cset *cset,
+				 struct zio_control *ctrl,
+				 fmode_t flags);
+	void (*destroy)(struct zio_ti *ti);
+
+Create and destroy a trigger instance for a cset. ZIO calls create() when
+attaching the trigger to a cset; it calls destroy() when the trigger is
+replaced by a different one or the cset is being unregistered from ZIO.
+The instance structure is trigger-specific, but it must include the
+generic structure zio_ti. Every time this structure is passed over, trigger
+code may use container_of if it needs to access the private enclosing
+structure.
+
+	int (*config)(struct zio_ti *ti, stuct zio_control *ctrl);
+
+The method is called by ZIO whenever the attributes for a trigger
+instance are modified by the user (by writing to sysfs or otherwise).
+
+	int (*push_block)(struct zio_ti *ti,
+			  struct zio_channel *chan,
+			  struct zio_control *ctrl);
+
+This is used for output channels: when a new data block is ready, it
+must be sent to the trigger so it can be output when the event fires.
+Buffer code, therefore, is expected to call this trigger method.  The
+function can return -EAGAIN if it has no space in the queue, or 0 on
+success. If EAGAIN happens, the buffer should handle it (by storing
+locally or notifying the user).
+
+	void (*pull_block)(struct zio_ti *ti,
+	  		   struct zio_channel *chan);
+
+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 of storing a block
+when available.  Since driver->input_cset 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.
+
+        void (*data_done)(struct zio_cset *cset);
+
+The function is called by the device, and signals the trigger that
+the input or output operation on the cset is over. For input, the
+trigger will push blocks to the buffer, for output it will release
+the blocks.  zio-core offers zio_generic_data_done() for triggers
+that don't need special handling.
+
+	File Operations
+	===============
+
+The trigger may include a non-NULL f_ops pointer. Most triggers will
+not need it, but for example "app-request" does, because it needs to
+look at individual read and write calls performed by applications.
+ZIO will use these file operations (instead of the buffer file operations)
+when the open method of the char device detects that the active trigger
+declares a non-NULL f_ops field.  These operations will most
+likely fall back to buffer->f_ops for most of their actual work.
+
+See zio-trig-app-request.c for details about how this is used.
+
+	When the trigger fires
+	======================
+
+The trigger event may happen for a variety of reasons. It can be
+time-driven, data-driven or whatever else.  In any case, there is
+a time when the trigger fires, so input or output may happen.
+(With most hardware-specific triggers, the actual input or output of
+data has already happened when the trigger interrupt runs, but this
+doesn't change the software flow).
+
+Hardware-driven triggers will need to make their own work by themselves,
+but ZIO offers this help macro to loop over all non-disabled channels:
+
+	cset_for_each(struct zio_cset *cset, struct zio_channel *ch)
+
+The macro works like "task_for_each" or "list_for_each" in the kernel
+headers.
+
+For software-based triggers (where actual I/O happens when software
+wants it to happen, even if it is in response to an interrupt), the
+asynchronous code that runs the event will just need to call
+
+	zio_fire_trigger(struct zio_ti *ti);
+
+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.
+
+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
+implementation based on trigger-local file_operations.
+
diff --git a/drivers/zio/README b/drivers/zio/README
new file mode 100644
index 0000000..d537353
--- /dev/null
+++ b/drivers/zio/README
@@ -0,0 +1,105 @@
+
+Zio is "the ultimate I/O framework".  Is being developed on the open
+hardware repository at http://www.ohwr.org/projects/zio .
+
+This version is known to compile and run with kernels 2.6.34 onwards.
+
+This README refers to version "beta3", but work is ongoing towards
+a stable package. See the TODO file on ohwr for details.
+
+To test zio you need to load the core modules (later, the default
+trigger and default buffer will be part of zio-core):
+
+   	insmod zio-core.ko
+   	insmod buffers/zio-buf-kmalloc.ko
+   	insmod triggers/zio-trig-timer.ko
+
+Drivers can't live without a trigger and a buffer, so the modules above
+must be loaded first.
+
+The kmalloc buffer is a simple buffer that hosts a list of data blocks,
+for either input or output.
+
+The timer trigger is a kernel-timer based trigger, that fires a block
+transfer on a timely basis. You can use the "ms" parameter to set the
+inter-block time, in milliseconds (the default is two seconds). You
+can also pass the "nsamples" parameter to say how many samples are
+aquired at each trigger instance.
+
+With the core in place, you can load a driver:
+
+	insmod drivers/zio-zero.ko
+
+zio-zero has a single channel-set (number 0) with three channels.
+They simulate three analog inputs, 8-bit per sample.
+
+     channel 0: returns zero forever
+     channel 1: returns random numbers
+     channel 2: returns a sawtooth signal (0 to 255 and back)
+
+The char devices are called using device-cset-channel:
+
+    /dev/zzero-0-0-ctrl
+    /dev/zzero-0-0-data
+    /dev/zzero-0-1-ctrl
+    /dev/zzero-0-1-data
+    /dev/zzero-0-2-ctrl
+    /dev/zzero-0-2-data
+
+(later versions will use a /dev/zio/ directory for all zio files)
+
+To read data you can just cat, or "od -t x1" the data device.
+To get control information meta-information) together with data, you
+can use the "zio-dump" user-space utility, in this directory.
+
+For example:
+
+    ./zio-dump /dev/zzero-0-2-ctrl /dev/zzero-0-2-data
+
+This is the result with a trigger that uses 2000 as msec and 32
+as nsample:
+
+    ./zio-dump /dev/zzero-0-2-ctrl /dev/zzero-0-2-data
+
+    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 2
+    Ctrl: seq 1, n 32, size 1, bits 8, flags 01000001 (little-endian)
+    Ctrl: stamp 1320403540.084798370 (0)
+    Data: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
+    Data: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
+
+    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 2
+    Ctrl: seq 2, n 32, size 1, bits 8, flags 01000001 (little-endian)
+    Ctrl: stamp 1320403542.091093781 (0)
+    Data: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
+    Data: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
+
+    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 2
+    Ctrl: seq 3, n 32, size 1, bits 8, flags 01000001 (little-endian)
+    Ctrl: stamp 1320403544.084790274 (0)
+    Data: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
+    Data: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
+
+Zio dump is able to access several pairs of devices (control and data),
+and you can change the trigger and buffer attributes for the cset.
+
+Example:
+
+    echo 500 > /sys/zio/devices/zzero/cset0/trigger/ms-period
+    echo 4 > /sys/zio/devices/zzero/cset0/trigger/nsamples
+    echo 3 > /sys/zio/devices/zzero/cset0/chan0/buffer/max-buffer-len
+    ./zio-dump /dev/zzero-0-*
+
+    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 0
+    Ctrl: seq 102, n 4, size 1, bits 8, flags 01000001 (little-endian)
+    Ctrl: stamp 4066.519285605 (0)
+    Data: 00 00 00 00
+
+    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 1
+    Ctrl: seq 102, n 4, size 1, bits 8, flags 01000001 (little-endian)
+    Ctrl: stamp 4066.519285605 (0)
+    Data: 71 29 a6 53
+
+    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 2
+    Ctrl: seq 102, n 4, size 1, bits 8, flags 01000001 (little-endian)
+    Ctrl: stamp 4066.519285605 (0)
+    Data: 60 61 62 63
-- 
1.7.7.2

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 2/7] include/linux: add headers for drivers/zio
  2011-11-26 17:30 [RFC PATCH 0/7] Introducing ZIO, a new I/O framework Alessandro Rubini
  2011-11-26 17:30 ` [RFC PATCH 1/7] Documentation: add docs for drivers/zio Alessandro Rubini
@ 2011-11-26 17:30 ` Alessandro Rubini
  2011-11-26 20:02   ` Greg KH
  2011-11-26 17:30 ` [RFC PATCH 3/7] drivers/zio: core files for the ZIO input/output Alessandro Rubini
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 25+ messages in thread
From: Alessandro Rubini @ 2011-11-26 17:30 UTC (permalink / raw)
  To: linux-iio, greg, linux-kernel
  Cc: federico.vaga, dcobas, siglesia, manohar.vanga

Header files for the beta3 release of zio.
The files match commit 7d37663 in git://ohwr.org/misc/zio.git .

Signed-off-by: Alessandro Rubini <rubini@gnudd.com>
Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
Acked-by: Juan David Gonzalez Cobas <dcobas@cern.ch>
Acked-by: Samuel Iglesias Gonsalvez <siglesia@cern.ch>
Acked-By: Manohar Vanga <manohar.vanga@cern.ch>
---
 include/linux/zio-buffer.h  |  246 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/zio-sysfs.h   |  122 +++++++++++++++++++++
 include/linux/zio-trigger.h |   99 +++++++++++++++++
 include/linux/zio.h         |  244 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 711 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/zio-buffer.h
 create mode 100644 include/linux/zio-sysfs.h
 create mode 100644 include/linux/zio-trigger.h
 create mode 100644 include/linux/zio.h

diff --git a/include/linux/zio-buffer.h b/include/linux/zio-buffer.h
new file mode 100644
index 0000000..2e5500c
--- /dev/null
+++ b/include/linux/zio-buffer.h
@@ -0,0 +1,246 @@
+/* Alessandro Rubini, Federico Vaga for CERN, 2011, GNU GPLv2 or later */
+#ifndef __ZIO_BUFFER_H__
+#define __ZIO_BUFFER_H__
+
+/*
+ * Data transfers on the control channel only happen by half a kB.
+ * This is fixed for forward compatibility; zio_control may have more
+ * fields in the future, and current apps should handle it.
+ */
+#define ZIO_CONTROL_SIZE	512
+
+/*
+ * The timestamp is mostly app-specific. It cam be timspec-alike but
+ * indidual devices may do whatever they want to match hardware.
+ */
+struct zio_timestamp {
+	uint64_t secs;
+	uint64_t ticks;
+	uint64_t bins;
+};
+
+/*
+ * The following data item is the control structure that is being exchanged
+ * on the control device associated to each data device. The size of each
+ * fields is fixed to ease portability of binary dumps (esp i386/x86-64).
+ * The endianness, however, is native for speed reasons.
+ */
+
+struct zio_control {
+	/* byte 0 */
+	uint8_t major_version;
+	uint8_t minor_version;
+	uint8_t unused[2];
+	/* byte 4*/
+	uint32_t seq_num;	/* block sequence number */
+	uint32_t flags;		/* endianness etc, see below */
+	uint32_t nsamples;	/* number of samples in this data block */
+	/* byte 16 */
+	uint16_t ssize;		/* sample-size for each of them, in bytes */
+	uint16_t sbits;		/* sample-bits: number of valid bits */
+	uint16_t cset_i;	/* index of channel-set within device */
+	uint16_t chan_i;	/* index of channel within cset */
+
+	/* byte 24 */
+	/* The control block includes what device the data belong to */
+	char devname[ZIO_NAME_LEN];
+
+	/* byte 56 */
+	/* Each data block is associated with a trigger and its features */
+	char triggername[ZIO_NAME_LEN];
+
+	/* byte 88 */
+	struct zio_timestamp tstamp;
+
+	/* byte 112 */
+	uint32_t ext_attr_mask;	/* mask of active extended attributes */
+	uint32_t std_attr_mask;	/* mask of active standard attributes */
+	/* byte 120 */
+	uint32_t std_attrs[32];	/* value of each standard attribute */
+	uint32_t ext_attrs[32];	/* value of each extended attribute */
+
+	/* This filler must be updated if you change fields above */
+	uint8_t __fill_end[ZIO_CONTROL_SIZE - 120 - 4 * (32 + 32)];
+};
+
+/* The following flags are used in the control structure */
+#define ZIO_CONTROL_LITTLE_ENDIAN	0x01000001
+#define ZIO_CONTROL_BIG_ENDIAN		0x02000002
+
+#define ZIO_CONTROL_MSB_ALIGN		0x00000004 /* for analog data */
+#define ZIO_CONTROL_LSB_ALIGN		0x00000008 /* for analog data */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
+#include <linux/zio.h>
+#include <linux/gfp.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+#define ZIO_DEFAULT_BUFFER "kmalloc" /* For devices with no own buffer type */
+
+/* Compile-time check that the control structure is the right size */
+static inline void __unused_check_size(void)
+{
+	/* if zio_control is smaller then ZIO_CONTROL_SIZE, compile error */
+	static int __used v1[sizeof(struct zio_control) - ZIO_CONTROL_SIZE];
+	/* if zio_control is greater then ZIO_CONTROL_SIZE, compile error */
+	static int __used v2[ZIO_CONTROL_SIZE - sizeof(struct zio_control)];
+
+	BUILD_BUG_ON(sizeof(struct zio_control) != ZIO_CONTROL_SIZE);
+}
+
+/* FIXME: use a kmem_cache and real functions for control alloc/free */
+static inline struct zio_control *zio_alloc_control(gfp_t gfp)
+{
+	struct zio_control *ctrl;
+
+	ctrl = kzalloc(sizeof(*ctrl), gfp);
+	if (!ctrl)
+		return NULL;
+	ctrl->major_version = ZIO_MAJOR_VERSION;
+	ctrl->minor_version = ZIO_MINOR_VERSION;
+	if (ntohl(1) == 1)
+		ctrl->flags |= ZIO_CONTROL_BIG_ENDIAN;
+	else
+		ctrl->flags |= ZIO_CONTROL_LITTLE_ENDIAN;
+	return ctrl;
+}
+static inline void zio_free_control(struct zio_control *ctrl)
+{
+	kfree(ctrl);
+}
+
+/*
+ * The following structure defines a buffer type, with methods.
+ * An instance is created for each channel using it
+ */
+struct zio_buffer_operations;
+struct zio_buffer_type {
+	struct zio_obj_head	head;
+	struct module		*owner;
+	struct list_head	list; /* instances, and list lock */
+	struct spinlock		lock;
+	unsigned long		flags; /* to be defined */
+
+	/* file operations (read/write etc) are buffer-specific too */
+	const struct zio_sys_operations		*s_op;
+	const struct zio_buffer_operations	*b_op;
+	const struct file_operations		*f_op;
+
+	/* default attributes for instance */
+	struct zio_attribute_set		zattr_set;
+	/* FIXME: how "own" devices are listed (here or elsewhere?) */
+	struct zio_device	*zdev_owner;
+	unsigned int		n_zdev_owner;
+};
+#define to_zio_buf(obj) container_of(obj, struct zio_buffer, head.kobj)
+
+/* read and write may often be the generic ones */
+ssize_t zio_generic_read(struct file *, char __user *,
+			 size_t, loff_t *);
+ssize_t zio_generic_write(struct file *, const char __user *,
+			  size_t, loff_t *);
+unsigned int zio_generic_poll(struct file *, struct poll_table_struct *);
+int zio_generic_release(struct inode *inode, struct file *f);
+
+
+int __must_check zio_register_buf(struct zio_buffer_type *zbuf,
+				  const char *name);
+void zio_unregister_buf(struct zio_buffer_type *zbuf);
+
+struct zio_bi {
+	struct zio_obj_head	head;
+	struct list_head	list;		/* instance list */
+	struct zio_channel	*chan;
+	struct zio_cset		*cset;		/* short for chan->cset */
+
+	/* Those using generic_read need this information */
+	unsigned long flags;			/* input or output, etc */
+	wait_queue_head_t q;			/* for reading or writing */
+
+	/* Standard and extended attributes for this object */
+	struct zio_attribute_set		zattr_set;
+
+	const struct zio_buffer_operations	*b_op;
+	const struct file_operations		*f_op;
+};
+#define to_zio_bi(_kobj) container_of(_kobj, struct zio_bi, head.kobj)
+
+/* The block is the basic data item being transferred */
+struct zio_block {
+	unsigned long		ctrl_flags;
+	void			*data;
+	size_t			datalen;
+	size_t			uoff;
+};
+
+/*
+ * We must know whether the ctrl block has been filled/read or not: "cdone"
+ * No "set_ctrl" or "clr_cdone" are needed, as cdone starts 0 and is only set
+ */
+#define zio_get_ctrl(block) ((struct zio_control *)((block)->ctrl_flags & ~1))
+#define zio_set_ctrl(block, ctrl) ((block)->ctrl_flags = (unsigned long)(ctrl))
+#define zio_is_cdone(block)  ((block)->ctrl_flags & 1)
+#define zio_set_cdone(block)  ((block)->ctrl_flags |= 1)
+
+
+/*
+ * Each buffer implementation must provide the following methods, because
+ * internal management of individual data instances is left to each of them.
+ *
+ * "store" is for input and "retr" for output (called by low-level driver).
+ * After store, the block is ready for user space and freed internally;
+ * after retr, it's the low level driver that must cal the free method.
+ * The "alloc" method is called on trigger setup (activate), because the
+ * data storage must be available when data transfer really happens (thus,
+ * a DMA-only device will have its own buffer as the preferred one).
+ * The buffer may use its own alloc for blocks created at write(2) time.
+ *
+ * Note that each buffer type will need more information, so the block
+ * is usually inside a custom structure, reached by container_of().
+ * Thus, all blocks for a buffer type must be allocated and freed using
+ * the methods of that specific buffer type.
+ */
+struct zio_buffer_operations {
+	struct zio_block *	(*alloc_block)(struct zio_bi *bi,
+					       struct zio_control *ctrl,
+					       size_t datalen, gfp_t gfp);
+	void			(*free_block)(struct zio_bi *bi,
+					      struct zio_block *block);
+
+	int			(*store_block)(struct zio_bi *bi,
+					       struct zio_block *block);
+	struct zio_block *	(*retr_block) (struct zio_bi *bi);
+
+	struct zio_bi *		(*create)(struct zio_buffer_type *zbuf,
+					  struct zio_channel *chan,
+					  fmode_t f_flags);
+	void			(*destroy)(struct zio_bi *bi);
+};
+
+/*
+ * This is the structure we place in f->private_data at open time.
+ * Note that the buffer_create function is called by zio-core.
+ */
+enum zio_cdev_type {
+	ZIO_CDEV_CTRL,
+	ZIO_CDEV_DATA,
+};
+struct zio_f_priv {
+	struct zio_channel *chan; /* where current block and buffer live */
+	enum zio_cdev_type type;
+};
+
+ssize_t zio_generic_read(struct file *f, char __user *ubuf,
+			 size_t count, loff_t *offp);
+ssize_t zio_generic_write(struct file *f, const char __user *ubuf,
+			  size_t count, loff_t *offp);
+unsigned int zio_generic_poll(struct file *f, struct poll_table_struct *w);
+
+#endif /* __KERNEL__ */
+#endif /* __ZIO_BUFFER_H__ */
diff --git a/include/linux/zio-sysfs.h b/include/linux/zio-sysfs.h
new file mode 100644
index 0000000..376b992
--- /dev/null
+++ b/include/linux/zio-sysfs.h
@@ -0,0 +1,122 @@
+/* Federico Vaga for CERN, 2011, GNU GPLv2 or later */
+#ifndef ZIO_SYSFS_H_
+#define ZIO_SYSFS_H_
+
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#include <linux/zio.h>
+
+/*
+ * zio_attribute: the attribute to access device parameters.
+ *
+ * Many devices store configuration in hardware registers, and thus
+ * many configuration steps can be reduced to a read/write from/to a
+ * particular device register, located at a specific address.
+ *
+ * A zio_attribute provides a generic way to access those registers
+ *
+ * @attribute: standard attribute structure used to create a sysfs access
+ * @priv.reg: register address to use as is
+ * @priv.reg_descriptor: a generic pointer used to specify how access to a
+ *	particular register on device. This is defined by driver developer
+ * @value: is the value stored on device
+ * @show: is equivalent to info_get from zio_operations
+ * @store: is equivalent to  conf_set from zio_operations
+ */
+struct zio_attribute {
+	struct attribute			attr;
+	union { /* priv is sometimes a pointer and sometimes an hw addr */
+		void				*ptr;
+		unsigned long			addr;
+	} priv;
+	uint32_t				value;
+	const struct zio_sys_operations		*s_op;
+};
+
+struct zio_sys_operations {
+	int (*info_get)(struct kobject *kobj, struct zio_attribute *zattr,
+			uint32_t *usr_val);
+	int (*conf_set)(struct kobject *kobj, struct zio_attribute *zattr,
+			uint32_t  usr_val);
+};
+
+/* attribute -> zio_attribute */
+#define to_zio_zattr(aptr) container_of(aptr, struct zio_attribute, attr)
+
+/*
+ * Every object has both std attributes (whole length is known)
+ * and extended attributes (as we need to be told how many).
+ * Then, the sysfs attribute_groups are what we build to actually register
+ */
+struct zio_attribute_set {
+	struct zio_attribute	*std_zattr;
+	unsigned int		n_std_attr;
+	struct attribute_group	std_group;
+	struct zio_attribute	*ext_zattr;
+	unsigned int		n_ext_attr;
+	struct attribute_group	ext_group;
+};
+
+enum zattr_standard_zdev {
+	ZATTR_NBIT,	/* number of bits per sample */
+	ZATTR_GAIN,	/* gain for signal, integer in 0.001 steps */
+	ZATTR_OFFSET,	/* microvolts */
+	ZATTR_MAXRATE,	/* hertz */
+	ZATTR_VREFTYPE,	/* source of Vref (0 = default) */
+	ZATTR_STD_NUM_ZDEV,		/* used to size arrays */
+};
+enum zattr_standard_trig {
+	ZATTR_TRIG_REENABLE = 0,/* re-arm trigger */
+	ZATTR_TRIG_NSAMPLES,	/* samples for each transfer */
+	ZATTR_STD_NUM_TRIG,	/* used to size arrays */
+};
+enum zattr_standard_zbuf {
+	ZATTR_ZBUF_MAXLEN = 0,	/* max number of element in buffer */
+	ZATTR_STD_NUM_ZBUF,	/* used to size arrays */
+};
+
+extern const char zio_zdev_attr_names[ZATTR_STD_NUM_ZDEV][ZIO_NAME_LEN];
+extern const char zio_trig_attr_names[ZATTR_STD_NUM_TRIG][ZIO_NAME_LEN];
+extern const char zio_zbuf_attr_names[ZATTR_STD_NUM_ZBUF][ZIO_NAME_LEN];
+
+
+/* FIXME: check this DECLARE stuff */
+#define DEFINE_ZATTR_STD(_type, _name) struct zio_attribute \
+	_name[ZATTR_STD_NUM_##_type]
+
+/*
+ * @ZATTR_REG: define a zio attribute with address register
+ * @ZATTR_PRV: define a zio attribute with private register
+ * @ZATTR_EXT_REG: define a zio extended attribute with address register
+ * @ZATTR_EXT_PRV: define a zio extended attribute with private register
+ */
+#define ZATTR_REG(zobj, _type, _mode, _add, _val)[_type] = {		\
+		.attr = {						\
+			.name = zio_##zobj##_attr_names[_type],		\
+			.mode = _mode					\
+		},							\
+		.priv.addr = _add,					\
+		.value = _val,						\
+}
+#define ZATTR_PRV(zobj, _type, _mode, _add, _val)[_type] = {		\
+		.attr = {						\
+			.name = zio_##zobj##_attr_names[_type],		\
+			.mode = _mode					\
+		},							\
+		.priv.ptr = _add,					\
+		.value = _val,						\
+}
+#define ZATTR_EXT_REG(_name, _mode, _add, _val) {			\
+		.attr = {.name = _name, .mode = _mode},			\
+		.priv.addr = _add,					\
+		.value = _val,						\
+}
+#define ZATTR_EXT_PRV(_name, _mode, _add, _val) {			\
+		.attr = {.name = _name, .mode = _mode},			\
+		.priv.ptr = _add,					\
+		.value = _val,						\
+}
+
+#endif /* ZIO_SYSFS_H_ */
diff --git a/include/linux/zio-trigger.h b/include/linux/zio-trigger.h
new file mode 100644
index 0000000..6afacfe
--- /dev/null
+++ b/include/linux/zio-trigger.h
@@ -0,0 +1,99 @@
+/* Federico Vaga for CERN, 2011, GNU GPLv2 or later */
+#ifndef __ZIO_TRIGGER_H__
+#define __ZIO_TRIGGER_H__
+
+#include <linux/zio.h>
+#include <linux/zio-buffer.h>
+
+#define ZIO_DEFAULT_TRIGGER "timer" /* FIXME: app-request */
+
+struct zio_trigger_type {
+	struct zio_obj_head	head;
+	struct module		*owner;
+	struct list_head	list; /* instances, and list lock */
+	struct spinlock		lock;
+	unsigned long		flags; /* to be defined */
+
+	/* file_operations because the trigger may override the buffer */
+	const struct zio_sys_operations		*s_op;
+	const struct zio_trigger_operations	*t_op;
+	const struct file_operations		*f_op;
+
+	/* default attributes for instance */
+	struct zio_attribute_set		zattr_set;
+
+	/* FIXME: how "own" devices are listed (here or elsewhere?) */
+	struct zio_device	*zdev_owner;
+	unsigned int		n_zdev_owner;
+};
+#define to_zio_trig(_kobj) container_of(_kobj, struct zio_trigger, head.kobj)
+
+int __must_check zio_register_trig(struct zio_trigger_type *ztrig,
+				   const char *name);
+void zio_unregister_trig(struct zio_trigger_type *trig);
+
+struct zio_ti {
+	struct zio_obj_head	head;
+	struct list_head	list;		/* instance list */
+	struct zio_cset		*cset;
+
+	unsigned long		flags;		/* input or output, etc */
+	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;
+
+	const struct zio_trigger_operations	*t_op;
+	const struct file_operations		*f_op;
+
+};
+#define to_zio_ti(_kobj) container_of(_kobj, struct zio_ti, head.kobj)
+void zio_fire_trigger(struct zio_ti *ti);
+
+/*
+ * When a buffer has a complete block of data, it can send it to the trigger
+ * using push_block. The trigger can either accept it (returns 0) or not
+ * (returns -EBUSY). This because an output  trigger has only one pending
+ * data transfer. When the block is consumed, the trigger may bi->retr_block
+ * to get the next one. Buffering is in the buffer, not in the trigger.
+ *
+ * For input channels, a buffer may call pull_block. The trigger may thus
+ * fire input directly and later have a block. In the normal case, the trigger
+ * runs by itself and it will call bi->store_block when a new block
+ * happens to be ready. In this case the pull_block method here may be null.
+ *
+ * Input and output in the device is almost always asynchronous, so when
+ * the data has been transferred for the cset, the device calls back the
+ * trigger. For output, data_done frees the blocks and prepares new
+ * blocks if possible; for input, data_done pushes material to the buffers.
+ *
+ * Then, a trigger instance is configured either by sysfs (and this means
+ * the conf_set callback runs and the instance is notified) or by writing
+ * a whole control to the control device. In this case the config method
+ * is called by the write method.
+ */
+struct zio_trigger_operations {
+	int			(*push_block)(struct zio_ti *ti,
+					      struct zio_channel *chan,
+					      struct zio_block *block);
+	void			(*pull_block)(struct zio_ti *ti,
+					      struct zio_channel *chan);
+
+	void			(*data_done)(struct zio_cset *cset);
+
+	int			(*config)(struct zio_ti *ti,
+					  struct zio_control *ctrl);
+
+	struct zio_ti *		(*create)(struct zio_trigger_type *trig,
+					  struct zio_cset *cset,
+					  struct zio_control *ctrl,
+					  fmode_t flags);
+	void			(*destroy)(struct zio_ti *ti);
+};
+
+void zio_generic_data_done(struct zio_cset *cest);
+
+#endif /* __ZIO_TRIGGER_H__ */
diff --git a/include/linux/zio.h b/include/linux/zio.h
new file mode 100644
index 0000000..992994b
--- /dev/null
+++ b/include/linux/zio.h
@@ -0,0 +1,244 @@
+
+/* Federico Vaga for CERN, 2011, GNU GPLv2 or later */
+#ifndef __ZIO_H__
+#define __ZIO_H__
+
+/* ZIO_VERSION: is a zio_class attribute to identify the framework version*/
+#define ZIO_MAJOR_VERSION 0
+#define ZIO_MINOR_VERSION 2
+
+#define ZIO_NAME_LEN 32 /* full name */
+
+#ifdef __KERNEL__ /* Nothing more is for user space */
+
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/string.h>
+
+#include <linux/zio-sysfs.h>
+
+/* These two maxima are kept low by now to test overflow situations */
+#define ZIO_CSET_MAXNUM 16
+#define ZIO_CHAN_MAXNUM 16
+
+#define ZIO_NMAX_CSET_MINORS (ZIO_CHAN_MAXNUM * 2)
+#define ZIO_NAME_OBJ 12 /* name for registered object */
+
+/* Name the data structures */
+struct zio_device; /* both type (a.k.a. driver) and instance (a.k.a. device) */
+struct zio_channel; struct zio_cset;
+struct zio_buffer_type; struct zio_bi; struct zio_block;
+struct zio_trigger_type; struct zio_ti;
+
+struct zio_device_operations;
+struct zio_buffer_operations;
+struct zio_trigger_operations;
+
+/*
+ * We use the same functions to deal with attributes, but the structures
+ * we act on may be different (dev, cset, channel). Thus, all structures
+ * begin with the type identifier, and zio_obj_head is used in container_of
+ */
+enum zio_object_type {
+	ZNONE = 0,	/* reserved for non zio object */
+	ZDEV, ZCSET, ZCHAN,
+	ZTRIG, ZTI,	/* trigger and trigger instance */
+	ZBUF, ZBI,	/* buffer and buffer instance */
+};
+
+/* zio_obj_head is for internal use only, as explained above */
+struct zio_obj_head {
+	struct kobject		kobj;
+	enum zio_object_type	zobj_type;
+	char			name[ZIO_NAME_LEN];
+};
+#define to_zio_head(_kobj) container_of(_kobj, struct zio_obj_head, kobj)
+#define to_zio_dev(_kobj) container_of(_kobj, struct zio_device, head.kobj)
+#define to_zio_cset(_kobj) container_of(_kobj, struct zio_cset, head.kobj)
+#define to_zio_chan(_kobj) container_of(_kobj, struct zio_channel, head.kobj)
+
+static inline enum zio_object_type __zio_get_object_type(struct kobject *kobj)
+{
+	return to_zio_head(kobj)->zobj_type;
+}
+
+/* Bits 0..3 are reserved for use in all objects. By now only bit 1 is used */
+enum zobj_flags {
+	ZIO_DISABLED		= 0x1,	/* 0 (default) is enabled */
+	ZIO_DIR			= 0x2,	/* 0 is input  - 1 is output*/
+	ZIO_DIR_INPUT		= 0x0,
+	ZIO_DIR_OUTPUT		= 0x2,
+};
+
+/*
+ * zio_device -- the top-level hardware description
+ */
+struct zio_device {
+	struct zio_obj_head			head;
+	struct module				*owner;
+	spinlock_t				lock; /* for all attr ops */
+	unsigned long				flags;
+	struct zio_attribute_set		zattr_set;
+	const struct zio_sys_operations		*s_op;
+	const struct zio_device_operations	*d_op;
+
+	/* The full device is an array of csets */
+	struct zio_cset			*cset;
+	unsigned int			n_cset;
+
+	/* We can state what its preferred buffer and trigger are (NULL ok) */
+	char *preferred_buffer;
+	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);
+
+/*
+ * zio_cset -- channel set: a group of channels with the same features
+ */
+struct zio_cset {
+	struct zio_obj_head	head;
+	struct zio_device	*zdev;		/* parent zio device */
+	struct zio_buffer_type	*zbuf;		/* buffer type for bi */
+	struct zio_trigger_type *trig;		/* trigger type for ti*/
+	struct zio_ti		*ti;		/* trigger instance */
+	unsigned		ssize;		/* sample size (bytes) */
+	unsigned		index;		/* index within parent */
+	unsigned long		flags;
+	struct zio_attribute_set zattr_set;
+	struct zio_attribute_set zattr_set_chan; /* model for channel attrs */
+
+	/* The cset is an array of channels */
+	struct zio_channel	*chan;
+	unsigned int		n_chan;
+
+	int (*init)(struct zio_cset *zcset);
+	void (*exit)(struct zio_cset *zcset);
+
+	struct list_head	list_cset;	/* for cset global list */
+	dev_t			basedev;	/* base for the minors */
+	char			zbuf_name[ZIO_NAME_OBJ];
+	char			trig_name[ZIO_NAME_OBJ];
+
+	struct zio_attribute	*cset_attrs; /* FIXME: set buf, set trig */
+};
+
+/* first 4bit are reserved for zio object universal flags */
+enum zcset_flags {
+	ZCSET_TYPE		= 0x10,	/* 0 is digital - 1 is analog*/
+	ZCSET_TYPE_DIGITAL	= 0x00,
+	ZCSET_TYPE_ANALOG	= 0x10,
+	ZCSET_CHAN_ALLOC	= 0x20, /* 1 if channels are allocated by zio*/
+	ZCSET_CHAN_ALLOC_ON	= 0x20,
+	ZCSET_CHAN_ALLOC_OFF	= 0x00,
+};
+
+/*
+ * zio_channel -- an individual channel within the cset
+ */
+
+struct zio_channel {
+	struct zio_obj_head	head;
+	struct zio_cset		*cset;		/* parent cset */
+	struct zio_ti		*ti;		/* cset trigger instance */
+	struct zio_bi		*bi;		/* buffer instance */
+	unsigned int		index;		/* index within parent */
+	unsigned long		flags;
+	struct zio_attribute_set zattr_set;
+
+	struct device		*ctrl_dev;	/* control char device */
+	struct device		*data_dev;	/* data char device */
+
+	struct zio_block	*user_block;	/* being transferred w/ user */
+	struct zio_block	*active_block;	/* being managed by hardware */
+};
+
+/* first 4bit are reserved for zio object universal flags */
+enum zchan_flag_mask {
+	ZCHAN_POLAR		= 0x10,	/* 0 is positive - 1 is negative*/
+	ZCHAN_POLAR_POSITIVE	= 0x00,
+	ZCHAN_POLAR_NEGATIVE	= 0x10,
+};
+
+/* get each channel from cset */
+static inline struct zio_channel *__first_enabled_chan(struct zio_cset *cset,
+						struct zio_channel *chan)
+{
+	if (unlikely(chan - cset->chan >= cset->n_chan))
+		return NULL;
+	while (1) {
+		if (!(chan->flags & ZIO_DISABLED))
+			return chan; /* if is enabled, use this */
+		if (chan->index+1 == cset->n_chan)
+			return NULL; /* no more channels */
+		chan++;
+	}
+}
+#define cset_for_each(cset, cptr)				\
+		for (cptr = cset->chan;				\
+		     (cptr = __first_enabled_chan(cset, cptr));	\
+		     cptr++)
+
+#ifdef __ZIO_INTERNAL__
+
+/* This list is used in the core to keep track of registered objects */
+struct zio_object_list {
+	struct kobject		*kobj;	/* for sysfs folder, no attrs */
+	enum zio_object_type	zobj_type;
+	struct list_head	list;
+};
+struct zio_object_list_item {
+	struct list_head	list;
+	char			name[ZIO_NAME_OBJ]; /* object name copy*/
+	struct module		*owner;
+	struct zio_obj_head	*obj_head;
+};
+
+/* Global framework status (i.e., globals in zio-core) */
+struct zio_status {
+	/* a pointer to set up standard ktype with create */
+	struct kobject		*kobj;
+	/*
+	 * The bmask represent the minors region for zio; each bit is
+	 * a block of minors available for a single cset. When a new cset
+	 * is declared, zio look for the first available block of minors:
+	 * set 1 to the correspondent bit on bitmask to set the block
+	 * as busy
+	 */
+	DECLARE_BITMAP(cset_minors_mask, ZIO_CSET_MAXNUM);
+	struct cdev		chrdev;
+	dev_t			basedev;
+	spinlock_t		lock;
+
+	/* List of cset, used to retrieve a cset from a minor base*/
+	struct list_head	list_cset;
+
+	/* The three lists of registered devices, with owner module */
+	struct zio_object_list	all_devices;
+	struct zio_object_list	all_trigger_types;
+	struct zio_object_list	all_buffer_types;
+};
+
+extern struct zio_status zio_global_status;
+int __zio_minorbase_get(struct zio_cset *zcset);
+void __zio_minorbase_put(struct zio_cset *zcset);
+
+int __zio_register_cdev(void);
+void __zio_unregister_cdev(void);
+
+int zio_create_chan_devices(struct zio_channel *zchan);
+void zio_destroy_chan_devices(struct zio_channel *zchan);
+#endif /* INTERNAL */
+
+#endif /* __KERNEL__ */
+#endif /* __ZIO_H__ */
-- 
1.7.7.2

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 3/7] drivers/zio: core files for the ZIO input/output
  2011-11-26 17:30 [RFC PATCH 0/7] Introducing ZIO, a new I/O framework Alessandro Rubini
  2011-11-26 17:30 ` [RFC PATCH 1/7] Documentation: add docs for drivers/zio Alessandro Rubini
  2011-11-26 17:30 ` [RFC PATCH 2/7] include/linux: add headers " Alessandro Rubini
@ 2011-11-26 17:30 ` Alessandro Rubini
  2011-11-26 20:03   ` Greg KH
  2011-11-26 17:30 ` [RFC PATCH 4/7] drivers/zio: add triggers and buffers Alessandro Rubini
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 25+ messages in thread
From: Alessandro Rubini @ 2011-11-26 17:30 UTC (permalink / raw)
  To: linux-iio, greg, linux-kernel
  Cc: federico.vaga, dcobas, siglesia, manohar.vanga

From: Federico Vaga <federico.vaga@gmail.com>

This adds the core files for ZIO.
The files match commit 7d37663 in git://ohwr.org/misc/zio.git .

The Makefile already includes material that is added by later
patches. This doesn't imply a compilation error as drivers/zio
is not yet being compiled by drivers/Makefile.

Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
Signed-off-by: Alessandro Rubini <rubini@gnudd.com>
Acked-by: Juan David Gonzalez Cobas <dcobas@cern.ch>
Acked-by: Samuel Iglesias Gonsalvez <siglesia@cern.ch>
Acked-by: Manohar Vanga <manohar.vanga@cern.ch>
---
 drivers/zio/Makefile   |   10 +
 drivers/zio/zio-cdev.c |  498 +++++++++++++++++
 drivers/zio/zio-sys.c  | 1423 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1931 insertions(+), 0 deletions(-)
 create mode 100644 drivers/zio/Makefile
 create mode 100644 drivers/zio/zio-cdev.c
 create mode 100644 drivers/zio/zio-sys.c

diff --git a/drivers/zio/Makefile b/drivers/zio/Makefile
new file mode 100644
index 0000000..fb5dd14
--- /dev/null
+++ b/drivers/zio/Makefile
@@ -0,0 +1,10 @@
+
+zio-core-objs := zio-cdev.o zio-sys.o
+obj-$(CONFIG_ZIO) += zio-core.o
+
+obj-$(CONFIG_ZIO) += drivers/
+obj-$(CONFIG_ZIO) += buffers/
+obj-$(CONFIG_ZIO) += triggers/
+
+hostprogs-y := zio-dump
+
diff --git a/drivers/zio/zio-cdev.c b/drivers/zio/zio-cdev.c
new file mode 100644
index 0000000..fae5749
--- /dev/null
+++ b/drivers/zio/zio-cdev.c
@@ -0,0 +1,498 @@
+/* Federico Vaga and Alessandro Rubini for CERN, 2011, GNU GPLv2 or later */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+
+#define __ZIO_INTERNAL__
+#include <linux/zio.h>
+#include <linux/zio-buffer.h>
+#include <linux/zio-trigger.h>
+
+static DEFINE_MUTEX(zmutex);
+struct zio_status zio_global_status;
+static struct zio_status *zstat = &zio_global_status; /* Always use ptr */
+
+static ssize_t zio_show_version(struct class *class,
+			struct class_attribute *attr,
+			char *buf)
+{
+	return sprintf(buf, "%d.%d\n", ZIO_MAJOR_VERSION, ZIO_MINOR_VERSION);
+}
+
+static struct class_attribute zclass_attrs[] = {
+	__ATTR(version, S_IRUGO, zio_show_version, NULL),
+	__ATTR_NULL,
+};
+
+static char *zio_devnode(struct device *dev, mode_t *mode)
+{
+	return kasprintf(GFP_KERNEL, "zio/%s", dev_name(dev));
+}
+
+/*
+ * zio_class: don't use class_create to create class because it doesn't permit
+ * to insert a set of class attributes. This structure is the exact
+ * reproduction of what class_create does but with some additional settings.
+ */
+static struct class zio_class = {
+	.name		= "zio",
+	.owner		= THIS_MODULE,
+	.class_attrs	= zclass_attrs,
+	.devnode	= zio_devnode,
+};
+
+/* Retrieve a channel from one of its minors */
+static struct zio_channel *__zio_minor_to_chan(dev_t mm)
+{
+	struct zio_cset *zcset;
+	dev_t cset_base, chan_minor;
+	int found = 0;
+
+	/* Extract cset minor base */
+	chan_minor = mm & (ZIO_NMAX_CSET_MINORS-1);
+	cset_base = mm & (~(ZIO_NMAX_CSET_MINORS-1));
+
+	/* Look for this minor base*/
+	list_for_each_entry(zcset, &zstat->list_cset, list_cset) {
+		if (cset_base == zcset->basedev) {
+			found = 1;
+			break;
+		}
+	}
+	if (!found)
+		return NULL;
+	return &zcset->chan[chan_minor/2];
+}
+
+static inline int zio_device_get(dev_t devt)
+{
+	struct zio_channel *chan;
+
+	/*
+	 * FIXME there is a little concurrency; to resolve this, get the owner
+	 * from device list by searching by minor
+	 */
+	chan = __zio_minor_to_chan(devt);
+	if (!chan) {
+		pr_err("ZIO: can't retrieve channel for minor %i\n",
+		       MINOR(devt));
+		return -EBUSY;
+	}
+	return try_module_get(chan->cset->zdev->owner);
+}
+static inline void zio_device_put(dev_t devt)
+{
+	struct zio_channel *chan;
+
+	/*
+	 * FIXME there is a little concurrency; to resolve this, get the owner
+	 * from device list by searching by minor
+	 */
+	chan = __zio_minor_to_chan(devt);
+	/* it is impossbile chan = NULL because __zio_device_get() found it */
+	module_put(chan->cset->zdev->owner);
+}
+
+static int zio_f_open(struct inode *ino, struct file *f)
+{
+	struct zio_f_priv *priv = NULL;
+	struct zio_channel *chan;
+	struct zio_buffer_type *zbuf;
+	const struct file_operations *old_fops, *new_fops;
+	int ret = -EINVAL, minor;
+
+	pr_debug("%s:%i\n", __func__, __LINE__);
+	if (f->f_flags & FMODE_WRITE)
+		goto out;
+
+	if (!zio_device_get(ino->i_rdev))
+		return -ENODEV;
+
+	minor = iminor(ino);
+	chan = __zio_minor_to_chan(ino->i_rdev);
+	if (!chan) {
+		pr_err("ZIO: can't retrieve channel for minor %i\n", minor);
+		return -EBUSY;
+	}
+	zbuf = chan->cset->zbuf;
+	f->private_data = NULL;
+	priv = kzalloc(sizeof(struct zio_f_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	/* if there is no instance, then create a new one */
+	if (!chan->bi)
+		chan->bi = zbuf->b_op->create(zbuf, chan, FMODE_READ);
+	priv->chan = chan;
+
+	/* even number is control, odd number is data */
+	if (minor & 0x1)
+		priv->type = ZIO_CDEV_DATA;
+	else
+		priv->type = ZIO_CDEV_CTRL;
+	f->private_data = priv;
+
+	/* replace zio fops with buffer fops (FIXME: make it a lib function */
+	mutex_lock(&zmutex);
+	old_fops = f->f_op;
+	new_fops = fops_get(zbuf->f_op);
+	ret = 0;
+	if (new_fops->open)
+		ret = new_fops->open(ino, f);
+	if (ret) {
+		fops_put(zbuf->f_op);
+		mutex_unlock(&zmutex);
+		goto out;
+	}
+	fops_put(old_fops);
+	f->f_op = new_fops;
+	mutex_unlock(&zmutex);
+	return 0;
+
+out:
+	kfree(priv);
+	return ret;
+}
+
+static const struct file_operations zfops = {
+	.owner = THIS_MODULE,
+	.open = zio_f_open,
+};
+
+int __zio_minorbase_get(struct zio_cset *zcset)
+{
+	int i;
+
+	i = find_first_zero_bit(zstat->cset_minors_mask, ZIO_CSET_MAXNUM);
+	if (i >= ZIO_CSET_MAXNUM)
+		return 1;
+	set_bit(i, zstat->cset_minors_mask);
+	/* set the base minor for a cset*/
+	zcset->basedev = zstat->basedev + (i * ZIO_NMAX_CSET_MINORS);
+	pr_debug("%s:%i BASEMINOR 0x%x\n", __func__, __LINE__, zcset->basedev);
+	return 0;
+}
+void __zio_minorbase_put(struct zio_cset *zcset)
+{
+	int i;
+
+	i = (zcset->basedev - zstat->basedev) / ZIO_NMAX_CSET_MINORS;
+	clear_bit(i, zstat->cset_minors_mask);
+}
+
+/*
+ * create control and data char devices for a channel. The even minor
+ * is for control, the odd one for data.
+ */
+int zio_create_chan_devices(struct zio_channel *chan)
+{
+	int err;
+	dev_t devt_c, devt_d;
+
+
+	devt_c = chan->cset->basedev + chan->index * 2;
+	pr_debug("%s:%d dev_t=0x%x\n", __func__, __LINE__, devt_c);
+	chan->ctrl_dev = device_create(&zio_class, NULL, devt_c, NULL,
+			"%s-%i-%i-ctrl",
+			chan->cset->zdev->head.name,
+			chan->cset->index,
+			chan->index);
+	if (IS_ERR(&chan->ctrl_dev)) {
+		err = PTR_ERR(&chan->ctrl_dev);
+		goto out;
+	}
+
+	devt_d = devt_c + 1;
+	pr_debug("%s:%d dev_t=0x%x\n", __func__, __LINE__, devt_d);
+	chan->data_dev = device_create(&zio_class, NULL, devt_d, NULL,
+			"%s-%i-%i-data",
+			chan->cset->zdev->head.name,
+			chan->cset->index,
+			chan->index);
+	if (IS_ERR(&chan->data_dev)) {
+		err = PTR_ERR(&chan->data_dev);
+		goto out_data;
+	}
+
+	return 0;
+
+out_data:
+	device_destroy(&zio_class, chan->ctrl_dev->devt);
+out:
+	return err;
+}
+
+void zio_destroy_chan_devices(struct zio_channel *chan)
+{
+	pr_debug("%s\n", __func__);
+	device_destroy(&zio_class, chan->data_dev->devt);
+	device_destroy(&zio_class, chan->ctrl_dev->devt);
+}
+
+int __zio_register_cdev()
+{
+	int err;
+
+	err = class_register(&zio_class);
+	if (err) {
+		pr_err("%s: unable to register class\n", __func__);
+		goto out;
+	}
+	/* alloc to zio the maximum number of minors usable in ZIO */
+	err = alloc_chrdev_region(&zstat->basedev, 0,
+			ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS, "zio");
+	if (err) {
+		pr_err("%s: unable to allocate region for %i minors\n",
+			__func__, ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS);
+		goto out;
+	}
+	/* all ZIO's devices, buffers and triggers has zfops as f_op */
+	cdev_init(&zstat->chrdev, &zfops);
+	zstat->chrdev.owner = THIS_MODULE;
+	err = cdev_add(&zstat->chrdev, zstat->basedev,
+			ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS);
+	if (err)
+		goto out_cdev;
+	INIT_LIST_HEAD(&zstat->list_cset);
+	return 0;
+out_cdev:
+	unregister_chrdev_region(zstat->basedev,
+			ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS);
+out:
+	class_unregister(&zio_class);
+	return err;
+}
+void __zio_unregister_cdev()
+{
+	cdev_del(&zstat->chrdev);
+	unregister_chrdev_region(zstat->basedev,
+				ZIO_CSET_MAXNUM * ZIO_NMAX_CSET_MINORS);
+	class_unregister(&zio_class);
+}
+
+
+/*
+ * Helper functions to check whether read and write would block. The
+ * return value is a poll(2) mask, so the poll method just calls them.
+ */
+
+/* Read is quite straightforward, as blocks reack us already filled */
+static int __zio_read_allowed(struct zio_f_priv *priv)
+{
+	struct zio_channel *chan = priv->chan;
+	struct zio_bi *bi = chan->bi;
+	const int can_read =  POLLIN | POLLRDNORM;
+
+	if (!chan->user_block)
+		chan->user_block = bi->b_op->retr_block(bi);
+	if (!chan->user_block)
+		return 0;
+
+	/* We have a block. So there is data and possibly control too */
+	if (likely(priv->type == ZIO_CDEV_DATA))
+		return can_read;
+
+	if (!zio_is_cdone(chan->user_block))
+		return POLLIN | POLLRDNORM;
+
+	/* There's a block, but we want to re-read control. Get a new block */
+	bi->b_op->free_block(bi, chan->user_block);
+	chan->user_block = bi->b_op->retr_block(bi);
+	if (!chan->user_block)
+		return 0;
+	return POLLIN | POLLRDNORM;
+}
+
+/* Write is more tricky: we need control, so we may ask it to the trigger */
+static struct zio_block *__zio_write_allocblock(struct zio_bi *bi,
+						 struct zio_control *ctrl)
+{
+	struct zio_block *block;
+	size_t datalen;
+
+	if (!ctrl) {
+		ctrl = zio_alloc_control(GFP_KERNEL);
+		if (!ctrl)
+			return NULL;
+		memcpy(ctrl, bi->cset->ti->current_ctrl, ZIO_CONTROL_SIZE);
+	}
+	datalen = ctrl->ssize * ctrl->nsamples;
+	block = bi->b_op->alloc_block(bi, ctrl, datalen, GFP_KERNEL);
+	return block;
+}
+
+static int __zio_write_allowed(struct zio_f_priv *priv)
+{
+	struct zio_channel *chan = priv->chan;
+	struct zio_bi *bi = chan->bi;
+	struct zio_block *block;
+	const int can_write = POLLOUT | POLLWRNORM;
+
+	if (priv->type == ZIO_CDEV_CTRL) {
+		/* Control is always writeable */
+		return can_write;
+	}
+
+	/* We want to write data. If we have no control, retrieve one */
+	if (!chan->user_block)
+		chan->user_block = __zio_write_allocblock(bi, NULL);
+	block = chan->user_block;
+	if (!block)
+		return 0;
+
+	/* If the block is not full, user can write data */
+	if (block->uoff < block->datalen)
+		return can_write;
+
+	/* Block is full: try to push out to the buffer */
+	if (bi->b_op->store_block(bi, block) < 0)
+		return 0;
+
+	/* We sent it: get a new one for this new data */
+	chan->user_block = __zio_write_allocblock(bi, NULL);
+	return chan->user_block ? can_write : 0;
+}
+
+/*
+ * The following "generic" read and write (and poll and so on) should
+ * work for most buffer types, and are exported for use in their
+ * buffer operations.
+ */
+ssize_t zio_generic_read(struct file *f, char __user *ubuf,
+			 size_t count, loff_t *offp)
+{
+	struct zio_f_priv *priv = f->private_data;
+	struct zio_channel *chan = priv->chan;
+	struct zio_bi *bi = chan->bi;
+	struct zio_block *block;
+
+	pr_debug("%s:%d type %s\n", __func__, __LINE__,
+		priv->type == ZIO_CDEV_CTRL ? "ctrl" : "data");
+
+	if (priv->type == ZIO_CDEV_CTRL && count < ZIO_CONTROL_SIZE)
+		return -EINVAL;
+
+	if ((bi->flags & ZIO_DIR) == ZIO_DIR_OUTPUT) {
+		/* FIXME: read_control for output channels is missing */
+		return -EINVAL;
+	}
+
+	if (!__zio_read_allowed(priv)) {
+		if (f->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		wait_event_interruptible(bi->q, __zio_read_allowed(priv));
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+	}
+	block = chan->user_block;
+
+	/* So, it's readable */
+	if (unlikely(priv->type == ZIO_CDEV_CTRL)) {
+		zio_set_cdone(block);
+		if (copy_to_user(ubuf, zio_get_ctrl(block), ZIO_CONTROL_SIZE))
+			return -EFAULT;
+		*offp += ZIO_CONTROL_SIZE;
+		return ZIO_CONTROL_SIZE;
+	}
+
+	/* Data file, and we have data */
+	if (count > block->datalen - block->uoff)
+		count = block->datalen - block->uoff;
+	if (copy_to_user(ubuf, block->data + block->uoff, count))
+		return -EFAULT;
+	*offp += count;
+	block->uoff += count;
+	if (block->uoff == block->datalen) {
+		chan->user_block = NULL;
+		bi->b_op->free_block(bi, block);
+	}
+	return count;
+}
+EXPORT_SYMBOL(zio_generic_read);
+
+ssize_t zio_generic_write(struct file *f, const char __user *ubuf,
+			  size_t count, loff_t *offp)
+{
+	struct zio_f_priv *priv = f->private_data;
+	struct zio_channel *chan = priv->chan;
+	struct zio_bi *bi = chan->bi;
+	struct zio_block *block;
+	struct zio_control *ctrl;
+
+	pr_debug("%s:%d type %s\n", __func__, __LINE__,
+		priv->type == ZIO_CDEV_CTRL ? "ctrl" : "data");
+
+	if ((bi->flags & ZIO_DIR) == ZIO_DIR_INPUT) {
+		/* FIXME: write_control for input channels is missing */
+		return -EINVAL;
+	}
+
+	if (!__zio_write_allowed(priv)) {
+		if (f->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		wait_event_interruptible(bi->q, __zio_write_allowed(priv));
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+	}
+
+	if (likely(priv->type == ZIO_CDEV_DATA)) {
+		/* Data is writeable, so we have space in this block */
+		block = chan->user_block;
+		if (count > block->datalen - block->uoff)
+			count =  block->datalen - block->uoff;
+		if (copy_from_user(block->data + block->uoff, ubuf, count))
+			return -EFAULT;
+		block->uoff += count;
+		if (block->uoff == block->datalen)
+			if (bi->b_op->store_block(bi, block) == 0)
+				chan->user_block = NULL;
+		return count;
+	}
+
+	/* Control: drop the current block and create a new one */
+	if (priv->type == ZIO_CDEV_CTRL && count < ZIO_CONTROL_SIZE)
+		return -EINVAL;
+	count = ZIO_CONTROL_SIZE;
+
+	if (chan->user_block)
+		bi->b_op->free_block(bi, chan->user_block);
+	chan->user_block = NULL;
+	ctrl = zio_alloc_control(GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+
+	if (copy_from_user(ctrl, ubuf, count))
+		return -EFAULT;
+	memcpy(bi->cset->ti->current_ctrl, ctrl, count);
+	*offp += count;
+	return count;
+}
+EXPORT_SYMBOL(zio_generic_write);
+
+unsigned int zio_generic_poll(struct file *f, struct poll_table_struct *w)
+{
+	struct zio_f_priv *priv = f->private_data;
+	struct zio_bi *bi = priv->chan->bi;
+
+	poll_wait(f, &bi->q, w);
+	return __zio_read_allowed(priv) | __zio_write_allowed(priv);
+}
+EXPORT_SYMBOL(zio_generic_poll);
+
+int zio_generic_release(struct inode *inode, struct file *f)
+{
+	struct zio_f_priv *priv = f->private_data;
+
+	/* priv is allocated by zio_f_open, must be freed */
+	kfree(priv);
+	zio_device_put(inode->i_rdev);
+	return 0;
+}
+EXPORT_SYMBOL(zio_generic_release);
+
diff --git a/drivers/zio/zio-sys.c b/drivers/zio/zio-sys.c
new file mode 100644
index 0000000..eef2491
--- /dev/null
+++ b/drivers/zio/zio-sys.c
@@ -0,0 +1,1423 @@
+/* Federico Vaga for CERN, 2011, GNU GPLv2 or later */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+
+#define __ZIO_INTERNAL__
+#include <linux/zio.h>
+#include <linux/zio-sysfs.h>
+#include <linux/zio-buffer.h>
+#include <linux/zio-trigger.h>
+
+static struct zio_status *zstat = &zio_global_status; /* Always use ptr */
+
+const char zio_zdev_attr_names[ZATTR_STD_NUM_ZDEV][ZIO_NAME_LEN] = {
+	[ZATTR_GAIN]		= "gain_factor",
+	[ZATTR_OFFSET]		= "offset",
+	[ZATTR_NBIT]		= "resolution-bits",
+	[ZATTR_MAXRATE]		= "max-sample-rate",
+	[ZATTR_VREFTYPE]	= "vref-src",
+};
+EXPORT_SYMBOL(zio_zdev_attr_names);
+const char zio_trig_attr_names[ZATTR_STD_NUM_TRIG][ZIO_NAME_LEN] = {
+	[ZATTR_TRIG_REENABLE]	= "re-enable",
+	[ZATTR_TRIG_NSAMPLES]	= "nsamples",
+};
+EXPORT_SYMBOL(zio_trig_attr_names);
+const char zio_zbuf_attr_names[ZATTR_STD_NUM_ZBUF][ZIO_NAME_LEN] = {
+	[ZATTR_ZBUF_MAXLEN]	= "max-buffer-len",
+};
+EXPORT_SYMBOL(zio_zbuf_attr_names);
+
+static const char *__get_sysfs_name(enum zio_object_type type, int i)
+{
+	const char *name;
+
+	switch (type) {
+	case ZDEV:
+		name = zio_zdev_attr_names[i];
+		break;
+	case ZTRIG:
+	case ZTI:
+		name = zio_trig_attr_names[i];
+		break;
+	case ZBUF:
+	case ZBI:
+		name = zio_zbuf_attr_names[i];
+		break;
+	default:
+		name = NULL;
+		break;
+	}
+
+	return name;
+}
+
+/*
+ * Top-level ZIO objects has a unique name.
+ * You can find a particular object by searching its name.
+ */
+static inline struct zio_object_list_item *__find_by_name(
+			struct zio_object_list *zobj_list, char *name)
+{
+	struct zio_object_list_item *cur;
+
+	if (!name)
+		return NULL;
+	list_for_each_entry(cur, &zobj_list->list, list) {
+		pr_debug("%s:%d %s=%s\n", __func__, __LINE__, cur->name, name);
+		if (strcmp(cur->name, name) == 0)
+			return cur; /* object found */
+	}
+	return NULL;
+}
+
+static inline struct zio_object_list_item *__zio_object_get(
+	struct zio_object_list *zobj_list, char *name)
+{
+	struct zio_object_list_item *list_item;
+
+	/* search for default trigger */
+	list_item = __find_by_name(zobj_list, name);
+	if (!list_item)
+		return NULL;
+	/* increment trigger usage to prevent rmmod */
+	if (!try_module_get(list_item->owner))
+		return NULL;
+	return list_item;
+}
+static struct zio_buffer_type *zio_buffer_get(char *name)
+{
+	struct zio_object_list_item *list_item;
+
+	list_item = __zio_object_get(&zstat->all_buffer_types, name);
+	if (!list_item)
+		return ERR_PTR(-ENODEV);
+	return container_of(list_item->obj_head, struct zio_buffer_type, head);
+}
+static inline void zio_buffer_put(struct zio_buffer_type *zbuf)
+{
+	pr_debug("%s:%d %p\n", __func__, __LINE__, zbuf->owner);
+	module_put(zbuf->owner);
+}
+static struct zio_trigger_type *zio_trigger_get(char *name)
+{
+	struct zio_object_list_item *list_item;
+
+	list_item = __zio_object_get(&zstat->all_trigger_types, name);
+	if (!list_item)
+		return ERR_PTR(-ENODEV);
+	return container_of(list_item->obj_head, struct zio_trigger_type, head);
+}
+static inline void zio_trigger_put(struct zio_trigger_type *trig)
+{
+	pr_debug("%s:%d %p\n", __func__, __LINE__, trig->owner);
+	module_put(trig->owner);
+}
+
+/* data_done is called by the driver, after {in,out}put_cset */
+void zio_generic_data_done(struct zio_cset *cset)
+{
+	struct zio_buffer_type *zbuf;
+	struct zio_device *zdev;
+	struct zio_channel *chan;
+	struct zio_block *block;
+	struct zio_ti *ti;
+	struct zio_bi *bi;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+
+	ti = cset->ti;
+	zdev = cset->zdev;
+	zbuf = cset->zbuf;
+
+	if (unlikely((ti->flags & ZIO_DIR) == ZIO_DIR_OUTPUT)) {
+		cset_for_each(cset, chan) {
+			bi = chan->bi;
+			block = chan->active_block;
+			if (block)
+				zbuf->b_op->free_block(chan->bi, block);
+			/* We may have a new block ready, or not */
+			chan->active_block = zbuf->b_op->retr_block(chan->bi);
+		}
+		return;
+	}
+	/* DIR_INPUT */
+	cset_for_each(cset, chan) {
+		bi = chan->bi;
+		block = chan->active_block;
+		if (!block)
+			continue;
+		if (zbuf->b_op->store_block(bi, block)) /* may fail, no prob */
+			zbuf->b_op->free_block(bi, block);
+	}
+}
+EXPORT_SYMBOL(zio_generic_data_done);
+
+static void __zio_fire_input_trigger(struct zio_ti *ti)
+{
+	struct zio_buffer_type *zbuf;
+	struct zio_block *block;
+	struct zio_device *zdev;
+	struct zio_cset *cset;
+	struct zio_channel *chan;
+	struct zio_control *ctrl;
+	int errdone = 0;
+
+	cset = ti->cset;
+	zdev = cset->zdev;
+	zbuf = cset->zbuf;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+
+	/* FIXME: check if a trigger is already pending */
+
+	/* Allocate the buffer for the incoming sample, in active channels */
+	cset_for_each(cset, chan) {
+		ctrl = zio_alloc_control(GFP_ATOMIC);
+		if (!ctrl) {
+			if (!errdone++)
+				pr_err("%s: can't alloc control\n", __func__);
+			continue;
+		}
+		memcpy(ctrl, ti->current_ctrl, ZIO_CONTROL_SIZE);
+		ctrl->chan_i = chan->index;
+
+		block = zbuf->b_op->alloc_block(chan->bi, ctrl,
+						ctrl->ssize * ctrl->nsamples,
+						GFP_ATOMIC);
+		if (IS_ERR(block)) {
+			if (!errdone++)
+				pr_err("%s: can't alloc block\n", __func__);
+			zio_free_control(ctrl);
+			continue;
+		}
+		chan->active_block = block;
+	}
+	if (zdev->d_op->input_cset(cset)) {
+		/* It succeeded immediately */
+		ti->t_op->data_done(cset);
+	}
+}
+
+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)) {
+		/* It succeeded immediately */
+		ti->t_op->data_done(cset);
+	}
+}
+
+/*
+ * When a software trigger fires, it should call this function. Hw ones don't
+ */
+void zio_fire_trigger(struct zio_ti *ti)
+{
+	/* If the trigger runs too early, ti->cset is still NULL */
+	if (!ti->cset)
+		return;
+
+	/* 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);
+	else
+		__zio_fire_output_trigger(ti);
+}
+EXPORT_SYMBOL(zio_fire_trigger);
+
+static int __has_auto_index(char *s)
+{
+	int i = 0;
+	for (i = 0; i < ZIO_NAME_LEN-1; i++) {
+		if (s[i] != '%')
+			continue;
+		i++;
+		if (s[i] == 'd')
+			return 1;
+	}
+	return 0;
+}
+static int __next_strlen(char *str)
+{
+	int increment = 0, i;
+
+	for (i = strlen(str)-1; i > 0; i--) {
+		/* if is an ascii number */
+		if (str[i] >= '0' && str[i] <= '9') {
+			if (str[i] == '9')
+				continue;
+			else
+				break;
+		} else {
+			increment++;
+			break;
+		}
+	}
+	return strlen(str) + increment;
+}
+
+/*
+ * The zio device name must be unique. If it is not unique, a busy error is
+ * returned.
+ */
+static int zobj_unique_name(struct zio_object_list *zobj_list, char *name)
+{
+	struct zio_object_list_item *cur;
+	struct zio_obj_head *tmp;
+	unsigned int counter = 0, again, len;
+	char name_to_check[ZIO_NAME_LEN];
+	int auto_index = __has_auto_index(name);
+
+	pr_debug("%s\n", __func__);
+
+	if (!name)
+		return -EINVAL;
+
+	len = strlen(name);
+	if (!len)
+		return -EINVAL;
+
+	strncpy(name_to_check, name, ZIO_NAME_LEN);
+	do {
+		again = 0;
+		if (auto_index) { /* TODO when zio become bus, it is useless */
+			sprintf(name_to_check, name, counter++);
+			len = strlen(name_to_check);
+		}
+
+		list_for_each_entry(cur, &zobj_list->list, list) {
+			tmp = cur->obj_head;
+			if (strcmp(tmp->name, name_to_check))
+				continue; /* no conflict */
+			/* conflict found */
+
+			/* if not auto-assigned, then error */
+			if (!auto_index) {
+				pr_err("ZIO: name \"%s\" is already taken\n",
+					name);
+				return -EBUSY;
+			}
+			/* build sequential name */
+			if (__next_strlen(name_to_check) > ZIO_NAME_LEN) {
+				pr_err("ZIO: invalid name \"%s\"\n", name);
+				return -EINVAL;
+			}
+			again = 1;
+			break;
+		}
+	} while (again);
+	strncpy(name, name_to_check, ZIO_NAME_LEN);
+	return 0;
+}
+
+static struct zio_attribute *__zattr_clone(const struct zio_attribute *src,
+		unsigned int n)
+{
+	struct zio_attribute *dest = NULL;
+	unsigned int size;
+
+	if (!src)
+		return NULL;
+	size = n * sizeof(struct zio_attribute);
+	dest = kmalloc(size, GFP_KERNEL);
+	if (!dest)
+		return NULL;
+
+	dest = memcpy(dest, src, size);
+
+	return dest;
+}
+
+static void __zattr_unclone(struct zio_attribute *zattr)
+{
+	kfree(zattr);
+}
+
+static int __zattr_set_copy(struct zio_attribute_set *dest,
+				     struct zio_attribute_set *src)
+{
+	if (!dest || !src)
+		return -EINVAL;
+	dest->n_std_attr = src->n_std_attr;
+	dest->n_ext_attr = src->n_ext_attr;
+	dest->std_zattr = __zattr_clone(src->std_zattr, dest->n_std_attr);
+	dest->ext_zattr = __zattr_clone(src->ext_zattr, dest->n_ext_attr);
+
+	return 0;
+}
+static void __zattr_set_free(struct zio_attribute_set *zattr_set)
+{
+	if (!zattr_set)
+		return;
+	__zattr_unclone(zattr_set->ext_zattr);
+	__zattr_unclone(zattr_set->std_zattr);
+}
+static int zattr_chan_pre_set(struct zio_channel *chan)
+{
+	struct zio_cset *cset = chan->cset;
+
+	if (!(cset->flags & ZCSET_CHAN_ALLOC))
+		return 0; /* nothing to do */
+
+	/*
+	 * If the channel has been allocated by ZIO, then attributes are
+	 * cloned from  the template channel description within parent cset
+	 */
+	chan->zattr_set.std_zattr =
+		__zattr_clone(
+			cset->zattr_set_chan.std_zattr,
+			ZATTR_STD_NUM_ZDEV);
+	if (IS_ERR(chan->zattr_set.std_zattr))
+		return PTR_ERR(chan->zattr_set.std_zattr);
+	chan->zattr_set.ext_zattr =
+		__zattr_clone(
+			cset->zattr_set.ext_zattr,
+			cset->zattr_set.n_ext_attr);
+	if (IS_ERR(chan->zattr_set.ext_zattr)) {
+		kfree(chan->zattr_set.std_zattr);
+		return PTR_ERR(chan->zattr_set.ext_zattr);
+	}
+	return 0;
+}
+
+static void zattr_chan_post_remove(struct zio_channel *chan)
+{
+	if (chan->cset->flags & ZCSET_CHAN_ALLOC) {
+		__zattr_unclone(chan->zattr_set.std_zattr);
+		__zattr_unclone(chan->zattr_set.ext_zattr);
+	}
+}
+
+/* When touching attributes, we always use the spinlock for the hosting dev */
+static spinlock_t *zdev_get_spinlock(struct zio_obj_head *head)
+{
+	spinlock_t *lock;
+
+	switch (head->zobj_type) {
+	case ZDEV:
+		lock = &to_zio_dev(&head->kobj)->lock;
+		break;
+	case ZCSET:
+		lock = &to_zio_cset(&head->kobj)->zdev->lock;
+		break;
+	case ZCHAN:
+		lock = &to_zio_chan(&head->kobj)->cset->zdev->lock;
+		break;
+	case ZTI: /* we might not want to take a lock but... */
+		lock = &to_zio_ti(&head->kobj)->cset->zdev->lock;
+		break;
+	case ZBI:
+		lock = &to_zio_bi(&head->kobj)->cset->zdev->lock;
+		break;
+	default:
+		WARN(1, "ZIO: unknown zio object %i\n", head->zobj_type);
+		return NULL;
+	}
+	return lock;
+}
+
+/* Retrieve an attribute set from an object head */
+static struct zio_attribute_set *__get_zattr_set(struct zio_obj_head *head)
+{
+	struct zio_attribute_set *zattr_set;
+
+	switch (head->zobj_type) {
+	case ZDEV:
+		zattr_set = &to_zio_dev(&head->kobj)->zattr_set;
+		break;
+	case ZCSET:
+		zattr_set = &to_zio_cset(&head->kobj)->zattr_set;
+		break;
+	case ZCHAN:
+		zattr_set = &to_zio_chan(&head->kobj)->zattr_set;
+		break;
+	case ZTRIG:
+		zattr_set = &to_zio_chan(&head->kobj)->zattr_set;
+		break;
+	case ZBUF:
+		zattr_set = &to_zio_chan(&head->kobj)->zattr_set;
+		break;
+	case ZTI:
+		zattr_set = &to_zio_ti(&head->kobj)->zattr_set;
+		break;
+	case ZBI:
+		zattr_set = &to_zio_bi(&head->kobj)->zattr_set;
+		break;
+	default:
+		WARN(1, "ZIO: unknown zio object %i\n", head->zobj_type);
+		return NULL;
+	}
+	return zattr_set;
+}
+
+ /*
+ * 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
+ * which handle binary 32-bit numbers. Both the function are locked to prevent
+ * concurrency issue when editing device register.
+ */
+static ssize_t zattr_show(struct kobject *kobj, struct attribute *attr,
+				char *buf)
+{
+	int err = 0;
+	ssize_t len = 0;
+	spinlock_t *lock;
+	struct zio_attribute *zattr = to_zio_zattr(attr);
+
+	pr_debug("%s\n", __func__);
+	if (unlikely(strcmp(attr->name, "name") == 0)) {
+		/* print device name*/
+		return sprintf(buf, "%s\n", to_zio_head(kobj)->name);
+	}
+
+	if (zattr->s_op->info_get) {
+		lock = zdev_get_spinlock(to_zio_head(kobj));
+		spin_lock(lock);
+		err = zattr->s_op->info_get(kobj, zattr, &zattr->value);
+		spin_unlock(lock);
+		if (err)
+			return err;
+	}
+	len = sprintf(buf, "%i\n", zattr->value);
+	return len;
+}
+static ssize_t zattr_store(struct kobject *kobj, struct attribute *attr,
+				const char *buf, size_t size)
+{
+	long val;
+	int err = 0;
+	struct zio_attribute *zattr = to_zio_zattr(attr);
+	spinlock_t *lock;
+
+	pr_debug("%s\n", __func__);
+	err = strict_strtol(buf, 0, &val);
+	if (err)
+		return -EINVAL;
+	if (zattr->s_op->conf_set) {
+		lock = zdev_get_spinlock(to_zio_head(kobj));
+		spin_lock(lock);
+		err = zattr->s_op->conf_set(kobj, zattr, val);
+		spin_unlock(lock);
+	}
+	return err == 0 ? size : err;
+}
+
+static const struct sysfs_ops zio_attribute_ktype_ops = {
+	.show  = zattr_show,
+	.store = zattr_store,
+};
+
+static struct attribute default_attrs[] = {
+		{
+			.name = "name", /* show the name */
+			.mode = 0444, /* read only */
+		},
+};
+static struct attribute *def_attr_ptr[] = {
+	&default_attrs[0],
+	NULL,
+};
+
+static struct kobj_type zdktype = { /* For standard and extended attribute */
+	.release   = NULL,
+	.sysfs_ops = &zio_attribute_ktype_ops,
+	.default_attrs = def_attr_ptr,
+};
+
+static mode_t zattr_is_visible(struct kobject *kobj, struct attribute *attr,
+				int n)
+{
+	unsigned int flag1, flag2, flag3;
+	mode_t mode = attr->mode;
+
+	/*
+	 * FIXME: if it's decided that activation
+	 * is always the first bit then is faster doing:
+	 * flag1 & flag2 & flag3 & 0x1
+	 * to verify content
+	 */
+	switch (__zio_get_object_type(kobj)) {
+	case ZDEV:
+		flag1 = to_zio_dev(kobj)->flags;
+		if (flag1 & ZIO_DISABLED)
+			mode = 0;
+		break;
+	case ZCSET:
+		flag1 = to_zio_cset(kobj)->flags;
+		flag2 = to_zio_cset(kobj)->zdev->flags;
+		if ((flag1 | flag2) & ZIO_DISABLED)
+			mode = 0;
+		break;
+	case ZCHAN:
+		flag1 = to_zio_chan(kobj)->flags;
+		flag2 = to_zio_chan(kobj)->cset->flags;
+		flag3 = to_zio_chan(kobj)->cset->zdev->flags;
+		if ((flag1 | flag2 | flag3) & ZIO_DISABLED)
+			mode = 0;
+		break;
+	case ZBI:
+		break;
+	case ZTI:
+		break;
+	default:
+		WARN(1, "ZIO: unknown zio object %i\n",
+		     __zio_get_object_type(kobj));
+	}
+
+	return mode;
+}
+
+/*
+ * Verify attributes within the group,
+ * If they are valid register the group
+ */
+static int zattr_create_group(struct kobject *kobj,
+			      struct zio_attribute *zattr,
+			      struct attribute_group *grp,
+			      unsigned int n_attr,
+			      const struct zio_sys_operations *s_op,
+			      int is_ext)
+{
+	int i;
+
+	pr_debug("%s\n", __func__);
+	if (!zattr || !n_attr) {
+		grp->attrs = NULL;
+		return 0;	/* no attributes */
+	}
+	/* extract the attributes */
+	grp->attrs = kzalloc(sizeof(struct attribute) * n_attr, GFP_KERNEL);
+	if (!grp->attrs)
+		return -ENOMEM;
+
+	grp->is_visible = zattr_is_visible;
+	for (i = 0; i < n_attr; i++) {
+		/* Add attribute and assign show and store functions */
+		grp->attrs[i] = &zattr[i].attr;
+		to_zio_zattr(grp->attrs[i])->s_op = s_op;
+		/* if not defined */
+		if (!grp->attrs[i]->name) {
+			if (is_ext) {
+				pr_warning("%s: can't create ext attributes. "
+				"%ith attribute has not a name", __func__, i);
+				return -EINVAL;
+			}
+			/*
+			 * Only standard attributes need these lines to fill
+			 * the empty hole in the array of attributes
+			 */
+			grp->attrs[i]->name = __get_sysfs_name(
+					to_zio_head(kobj)->zobj_type, i);
+			grp->attrs[i]->mode = 0;
+		}
+		/* if write permission but no write function */
+		if ((grp->attrs[i]->mode & S_IWUGO) == S_IWUGO &&
+		     !s_op->conf_set) {
+			pr_err("%s: %s has write permission but no write "
+				"function\n", __func__, grp->attrs[i]->name);
+			return -EINVAL;
+		}
+	}
+	return sysfs_create_group(kobj, grp);
+}
+
+
+/* Create a set of zio attributes: the standard one and the extended one */
+static void zattr_remove_group(struct kobject *kobj,
+			       struct attribute_group *grp)
+{
+	if (!grp->attrs)
+		return;
+	sysfs_remove_group(kobj, grp);
+	kfree(grp->attrs);
+}
+/* create a set of zio attributes: the standard one and the extended one */
+static int zattr_set_create(struct zio_obj_head *head,
+			    const struct zio_sys_operations *s_op)
+{
+	int err = 0;
+	struct zio_attribute_set *zattr_set;
+
+	zattr_set = __get_zattr_set(head);
+	if (!zattr_set)
+		return -EINVAL; /* message already printed */
+
+	/* Create the standard attributes from zio attributes */
+	err = zattr_create_group(&head->kobj, zattr_set->std_zattr,
+		&zattr_set->std_group, zattr_set->n_std_attr, s_op, 0);
+	if (err)
+		goto out;
+	/* Create the extended attributes from zio attributes */
+	err = zattr_create_group(&head->kobj, zattr_set->ext_zattr,
+		&zattr_set->ext_group, zattr_set->n_ext_attr, s_op, 1);
+	if (err && zattr_set->std_group.attrs)
+		sysfs_remove_group(&head->kobj, &zattr_set->std_group);
+out:
+	return err;
+}
+/* Remove an existent set of attributes */
+static void zattr_set_remove(struct zio_obj_head *head)
+{
+	struct zio_attribute_set *zattr_set;
+
+	zattr_set = __get_zattr_set(head);
+	if (!zattr_set)
+		return;
+
+	/* remove the standard attribute group */
+	zattr_remove_group(&head->kobj, &zattr_set->std_group);
+	/* remove the extended attribute group */
+	zattr_remove_group(&head->kobj, &zattr_set->ext_group);
+}
+
+/* Create a buffer instance according to the buffer type defined in cset */
+static int __buffer_create_instance(struct zio_channel *chan)
+{
+	struct zio_buffer_type *zbuf = chan->cset->zbuf;
+	struct zio_bi *bi;
+	int err;
+
+	/* create buffer */
+	bi = zbuf->b_op->create(zbuf, chan, FMODE_READ);
+	if (IS_ERR(bi))
+		return PTR_ERR(bi);
+	/* Now fill the trigger instance, ops, head, then the rest */
+	bi->b_op = zbuf->b_op;
+	bi->f_op = zbuf->f_op;
+	bi->flags |= (chan->flags & ZIO_DIR);
+	bi->head.zobj_type = ZBI;
+	err = kobject_init_and_add(&bi->head.kobj, &zdktype,
+			&chan->head.kobj, "buffer");
+	if (err)
+		goto out_kobj;
+	snprintf(bi->head.name, ZIO_NAME_LEN, "%s-%s-%d-%d",
+			zbuf->head.name,
+			chan->cset->zdev->head.name,
+			chan->cset->index,
+			chan->index);
+
+	err = __zattr_set_copy(&bi->zattr_set, &zbuf->zattr_set);
+	if (err)
+		goto out_clone;
+	err = zattr_set_create(&bi->head, zbuf->s_op);
+	if (err)
+		goto out_sysfs;
+	init_waitqueue_head(&bi->q);
+
+	/* Add to buffer instance list */
+	spin_lock(&zbuf->lock);
+	list_add(&bi->list, &zbuf->list);
+	spin_unlock(&zbuf->lock);
+	bi->cset = chan->cset;
+	chan->bi = bi;
+
+	/* Done. This cset->ti marks everything is running (FIXME?) */
+	mb();
+	bi->chan = chan;
+
+	return 0;
+
+out_sysfs:
+	__zattr_set_free(&bi->zattr_set);
+out_clone:
+	kobject_del(&bi->head.kobj);
+out_kobj:
+	kobject_put(&bi->head.kobj);
+	zbuf->b_op->destroy(bi);
+	return err;
+}
+
+/* Destroy a buffer instance */
+static void __buffer_destroy_instance(struct zio_channel *chan)
+{
+	struct zio_buffer_type *zbuf = chan->cset->zbuf;
+	struct zio_bi *bi = chan->bi;
+
+	chan->bi = NULL;
+
+	/* Remove from buffer instance list */
+	spin_lock(&zbuf->lock);
+	list_del(&bi->list);
+	spin_unlock(&zbuf->lock);
+	/* Remove from sysfs */
+	zattr_set_remove(&bi->head);
+	__zattr_set_free(&bi->zattr_set);
+	kobject_del(&bi->head.kobj);
+	kobject_put(&bi->head.kobj);
+	/* Finally destroy the instance */
+	zbuf->b_op->destroy(bi);
+}
+
+/* Create a trigger instance according to the trigger type defined in cset */
+static int __trigger_create_instance(struct zio_cset *cset)
+{
+	int err;
+	struct zio_control *ctrl;
+	struct zio_ti *ti;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	/* Allocate and fill current control as much as possible*/
+	ctrl = zio_alloc_control(GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+	ctrl->cset_i = cset->index;
+	strncpy(ctrl->devname, cset->zdev->head.name, ZIO_NAME_LEN);
+	strncpy(ctrl->triggername, cset->trig->head.name, ZIO_NAME_LEN);
+	ctrl->sbits = 8; /* FIXME: retrieve from attribute */
+	ctrl->ssize = cset->ssize;
+
+	ti = cset->trig->t_op->create(cset->trig, cset, ctrl, 0/*FIXME*/);
+	if (IS_ERR(ti)) {
+		err = PTR_ERR(ti);
+		pr_err("%s: can't create trigger error %i\n", __func__, err);
+		goto out;
+	}
+	/* Now fill the trigger instance, ops, head, then the rest */
+	ti->t_op = cset->trig->t_op;
+	ti->f_op = cset->trig->f_op;
+	ti->flags |= cset->flags & ZIO_DIR;
+	ti->head.zobj_type = ZTI;
+	err = kobject_init_and_add(&ti->head.kobj, &zdktype,
+		&cset->head.kobj, "trigger");
+	if (err)
+		goto out_kobj;
+	snprintf(ti->head.name, ZIO_NAME_LEN, "%s-%s-%d",
+			cset->trig->head.name,
+			cset->zdev->head.name,
+			cset->index);
+
+	err = __zattr_set_copy(&ti->zattr_set, &cset->trig->zattr_set);
+	if (err)
+		goto out_clone;
+	err = zattr_set_create(&ti->head, cset->trig->s_op);
+	if (err)
+		goto out_sysfs;
+
+	/* Add to trigger instance list */
+	spin_lock(&cset->trig->lock);
+	list_add(&ti->list, &cset->trig->list);
+	spin_unlock(&cset->trig->lock);
+	cset->ti = ti;
+
+	/* Done. This cset->ti marks everything is running (FIXME?) */
+	mb();
+	ti->cset = cset;
+
+	return 0;
+
+out_sysfs:
+	__zattr_set_free(&ti->zattr_set);
+out_clone:
+	kobject_del(&ti->head.kobj);
+out_kobj:
+	kobject_put(&ti->head.kobj);
+	ti->t_op->destroy(ti);
+out:
+	zio_free_control(ctrl);
+	return err;
+}
+
+/* Destroy a buffer instance */
+static void __trigger_destroy_instance(struct zio_cset *cset)
+{
+	struct zio_ti *ti = cset->ti;
+	struct zio_control *ctrl = ti->current_ctrl;
+
+	cset->ti = NULL;
+
+	/* Remove from trigger instance list */
+	spin_lock(&cset->trig->lock);
+	list_del(&ti->list);
+	spin_unlock(&cset->trig->lock);
+	/* Remove from sysfs */
+	zattr_set_remove(&ti->head);
+	__zattr_set_free(&ti->zattr_set);
+	kobject_del(&ti->head.kobj);
+	kobject_put(&ti->head.kobj);
+	/* Finally destroy the instance and free the default control*/
+	cset->trig->t_op->destroy(ti);
+	zio_free_control(ctrl);
+}
+
+/*
+ * chan_register registers one channel.  It is important to register
+ * or unregister all the channels of a cset at the same time to prevent
+ * overlaps in the minors.
+ */
+static int chan_register(struct zio_channel *chan)
+{
+	int err;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	if (!chan)
+		return -EINVAL;
+
+	chan->head.zobj_type = ZCHAN;
+	err = kobject_init_and_add(&chan->head.kobj, &zdktype,
+			&chan->cset->head.kobj, "chan%i", chan->index);
+	if (err)
+		goto out_add;
+
+	err = zattr_chan_pre_set(chan);
+	if (err)
+		goto out_pre;
+
+	/* Create sysfs channel attributes */
+	err = zattr_set_create(&chan->head, chan->cset->zdev->s_op);
+	if (err)
+		goto out_sysfs;
+
+	/* Create buffer */
+	err = __buffer_create_instance(chan);
+	if (err)
+		goto out_buf;
+
+	/* Create channel char devices*/
+	err = zio_create_chan_devices(chan);
+	if (err)
+		goto out_create;
+	/*
+	 * If no name was assigned, ZIO assigns it.  channel name is
+	 * set to the kobject name. kobject name has no length limit,
+	 * so the channel name is the first ZIO_NAME_LEN characters of
+	 * kobject name. A duplicate channel name is not a problem
+	 * anyways.
+	 */
+	if (!strlen(chan->head.name))
+		strncpy(chan->head.name, chan->head.kobj.name, ZIO_NAME_LEN);
+	return 0;
+
+out_create:
+	__buffer_destroy_instance(chan);
+out_buf:
+	zattr_set_remove(&chan->head);
+out_sysfs:
+	zattr_chan_post_remove(chan);
+out_pre:
+	kobject_del(&chan->head.kobj);
+out_add:
+	/* we must _put even if it returned error */
+	kobject_put(&chan->head.kobj);
+	return err;
+}
+
+static void chan_unregister(struct zio_channel *chan)
+{
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	if (!chan)
+		return;
+	zio_destroy_chan_devices(chan);
+	/* destroy buffer instance */
+	__buffer_destroy_instance(chan);
+	/* remove sysfs cset attributes */
+	zattr_set_remove(&chan->head);
+	zattr_chan_post_remove(chan);
+	kobject_del(&chan->head.kobj);
+	kobject_put(&chan->head.kobj);
+}
+
+/*
+ * @cset_alloc_chan: low-level drivers can avoid allocating their channels,
+ * they say how many are there and ZIO allocates them.
+ * @cset_free_chan: if ZIO allocated channels, then it frees them; otherwise
+ * it does nothing.
+ */
+static struct zio_channel *cset_alloc_chan(struct zio_cset *cset)
+{
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	/*if no static channels, then ZIO must alloc them */
+	if (cset->chan)
+		return cset->chan;
+	/* initialize memory to zero to have correct flags and attrs */
+	cset->chan = kzalloc(sizeof(struct zio_channel) *
+					cset->n_chan, GFP_KERNEL);
+	if (!cset->chan)
+		return ERR_PTR(-ENOMEM);
+	cset->flags |= ZCSET_CHAN_ALLOC;
+
+	return cset->chan;
+}
+static inline void cset_free_chan(struct zio_cset *cset)
+{
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	/* Only allocated channels need to be freed */
+	if (cset->flags & ZCSET_CHAN_ALLOC)
+		kfree(cset->chan);
+}
+
+static int cset_register(struct zio_cset *cset)
+{
+	int i, j, err = 0;
+	struct zio_buffer_type *zbuf;
+	struct zio_trigger_type *trig;
+	char *name;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	if (!cset)
+		return -EINVAL;
+
+	if (!cset->n_chan) {
+		pr_err("ZIO: no channels in cset%i\n", cset->index);
+		return -EINVAL;
+	}
+
+	if (!cset->ssize) {
+		pr_err("ZIO: ssize can not be 0 in cset%i\n", cset->index);
+		return -EINVAL;
+	}
+
+	/* Get an available minor base */
+	err = __zio_minorbase_get(cset);
+	if (err) {
+		pr_err("ZIO: no minors available\n");
+		return -EBUSY;
+	}
+
+	cset->head.zobj_type = ZCSET;
+	err = kobject_init_and_add(&cset->head.kobj, &zdktype,
+			&cset->zdev->head.kobj, "cset%i", cset->index);
+	if (err)
+		goto out_add;
+	/* Create sysfs cset attributes */
+	err = zattr_set_create(&cset->head, cset->zdev->s_op);
+	if (err)
+		goto out_sysfs;
+
+	cset->chan = cset_alloc_chan(cset);
+	if (IS_ERR(cset->chan)) {
+		err = PTR_ERR(cset->chan);
+		goto out_alloc;
+	}
+
+	/*
+	 * The cset must have a buffer type. If none is associated
+	 * to the cset, ZIO selects the preferred or default one.
+	 */
+	if (!cset->zbuf) {
+		name = cset->zdev->preferred_buffer;
+		zbuf = zio_buffer_get(name);
+		if (name && IS_ERR(zbuf))
+			pr_warning("%s: no buffer \"%s\" (error %li), using "
+				   "default\n", __func__, name, PTR_ERR(zbuf));
+		if (IS_ERR(zbuf))
+			zbuf = zio_buffer_get(ZIO_DEFAULT_BUFFER);
+		if (IS_ERR(zbuf)) {
+			err = PTR_ERR(zbuf);
+			goto out_buf;
+		}
+		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;
+	}
+
+	/*
+	 * If no name was assigned, ZIO assigns it.  cset name is
+	 * set to the kobject name. kobject name has no length limit,
+	 * so the cset name is the first ZIO_NAME_LEN characters of
+	 * kobject name. A duplicate cset name is not a problem
+	 * anyways.
+	 */
+	if (!strlen(cset->head.name))
+		strncpy(cset->head.name, cset->head.kobj.name, ZIO_NAME_LEN);
+
+	/*
+	 * The cset must have a trigger type. If none  is associated
+	 * to the cset, ZIO selects the default or preferred one.
+	 * This is done late because each channel must be ready when
+	 * the trigger fires.
+	 */
+	if (!cset->trig) {
+		name = cset->zdev->preferred_trigger;
+		trig = zio_trigger_get(name);
+		if (name && IS_ERR(trig))
+			pr_warning("%s: no trigger \"%s\" (error %li), using "
+				   "default\n", __func__, name, PTR_ERR(trig));
+		if (IS_ERR(trig))
+			trig = zio_trigger_get(ZIO_DEFAULT_TRIGGER);
+		if (IS_ERR(trig)) {
+			err = PTR_ERR(trig);
+			goto out_trig;
+		}
+		cset->trig = trig;
+		err = __trigger_create_instance(cset);
+		if (err)
+			goto out_trig;
+	}
+
+	list_add(&cset->list_cset, &zstat->list_cset);
+
+	/* Private initialization function */
+	if (cset->init) {
+		err = cset->init(cset);
+		if (err)
+			goto out_init;
+	}
+	return 0;
+
+out_init:
+	__trigger_destroy_instance(cset);
+out_trig:
+	zio_trigger_put(cset->trig);
+	cset->trig = NULL;
+out_reg:
+	for (j = i-1; j >= 0; j--)
+		chan_unregister(&cset->chan[j]);
+	zio_buffer_put(cset->zbuf);
+out_buf:
+	cset_free_chan(cset);
+out_alloc:
+	zattr_set_remove(&cset->head);
+out_sysfs:
+	kobject_del(&cset->head.kobj);
+out_add:
+	/* we must _put even if it returned error */
+	kobject_put(&cset->head.kobj);
+	return err;
+}
+
+static void cset_unregister(struct zio_cset *cset)
+{
+	int i;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	if (!cset)
+		return;
+	/* Private exit function */
+	if (cset->exit)
+		cset->exit(cset);
+
+	/* Remove from csets list*/
+	list_del(&cset->list_cset);
+	/* destroy instance and decrement trigger usage */
+	__trigger_destroy_instance(cset);
+	zio_trigger_put(cset->trig);
+	cset->trig = NULL;
+	/* Unregister all child channels */
+	for (i = 0; i < cset->n_chan; i++)
+		chan_unregister(&cset->chan[i]);
+	/* decrement buffer usage */
+	zio_buffer_put(cset->zbuf);
+	cset->zbuf = NULL;
+	cset_free_chan(cset);
+	/* Remove from sysfs */
+	zattr_set_remove(&cset->head);
+	kobject_del(&cset->head.kobj);
+	kobject_put(&cset->head.kobj);
+	/* Release a group of minors */
+	__zio_minorbase_put(cset);
+}
+
+/*
+ * Register a generic zio object. It can be a device, a buffer type or
+ * a trigger type.
+ */
+static int zobj_register(struct zio_object_list *zlist,
+			 struct zio_obj_head *head,
+			 enum zio_object_type type,
+			 struct module *owner,
+			 const char *name)
+{
+	int err;
+	struct zio_object_list_item *item;
+
+	head->zobj_type = type;
+	if (strlen(name) > ZIO_NAME_OBJ)
+		pr_warning("ZIO: name too long, cut to %d characters\n",
+			   ZIO_NAME_OBJ);
+	strncpy(head->name, name, ZIO_NAME_OBJ);
+
+	/* Name must be unique */
+	err = zobj_unique_name(zlist, head->name);
+	if (err)
+		goto out;
+	err = kobject_init_and_add(&head->kobj, &zdktype, zlist->kobj,
+					head->name);
+	if (err)
+		goto out_kobj;
+
+	/* Add to object list */
+	item = kmalloc(sizeof(struct zio_object_list_item), GFP_KERNEL);
+	if (!item) {
+		err = -ENOMEM;
+		goto out_km;
+	}
+	item->obj_head = head;
+	item->owner = owner;
+	strncpy(item->name, head->name, ZIO_NAME_OBJ);
+	/* add to the object list*/
+	spin_lock(&zstat->lock);
+	list_add(&item->list, &zlist->list);
+	spin_unlock(&zstat->lock);
+	return 0;
+
+out_km:
+	kobject_del(&head->kobj);
+out_kobj:
+	kobject_put(&head->kobj); /* we must _put even if it returned error */
+out:
+	return err;
+}
+static void zobj_unregister(struct zio_object_list *zlist,
+		struct zio_obj_head *zobj)
+{
+	struct zio_object_list_item *item;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	if (!zobj)
+		return;
+	list_for_each_entry(item, &zlist->list, list) {
+		if (item->obj_head == zobj) {
+			/* Remove from object list */
+			spin_lock(&zstat->lock);
+			list_del(&item->list);
+			spin_unlock(&zstat->lock);
+			kfree(item);
+			break;
+		}
+	}
+
+	kobject_del(&zobj->kobj);
+	kobject_put(&zobj->kobj);
+}
+
+/* Register a zio device */
+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;
+	}
+	/* Register the device */
+	err = zobj_register(&zstat->all_devices, &zdev->head,
+			    ZDEV, zdev->owner, name);
+	if (err)
+		goto out;
+	zdev->zattr_set.n_std_attr = ZATTR_STD_NUM_ZDEV;
+	spin_lock_init(&zdev->lock);
+	/* Create standard and extended sysfs attribute for device */
+	err = zattr_set_create(&zdev->head, zdev->s_op);
+	if (err)
+		goto out_sysfs;
+
+	/* Register all child channel sets */
+	for (i = 0; i < zdev->n_cset; i++) {
+		zdev->cset[i].index = i;
+		zdev->cset[i].zdev = zdev;
+		err = cset_register(&zdev->cset[i]);
+		if (err)
+			goto out_cset;
+	}
+
+	return 0;
+
+out_cset:
+	for (j = i-1; j >= 0; j--)
+		cset_unregister(zdev->cset + j);
+out_sysfs:
+	zobj_unregister(&zstat->all_devices, &zdev->head);
+out:
+	return err;
+}
+EXPORT_SYMBOL(zio_register_dev);
+
+void zio_unregister_dev(struct zio_device *zdev)
+{
+	int i;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	if (!zdev)
+		return;
+
+	/* Unregister all child channel sets */
+	for (i = 0; i < zdev->n_cset; i++)
+		cset_unregister(&zdev->cset[i]);
+	/* Remove from sysfs */
+	zattr_set_remove(&zdev->head);
+	/* Unregister the device */
+	zobj_unregister(&zstat->all_devices, &zdev->head);
+}
+EXPORT_SYMBOL(zio_unregister_dev);
+
+/* Register a buffer into the available buffer list */
+int zio_register_buf(struct zio_buffer_type *zbuf, const char *name)
+{
+	int err;
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	if (!zbuf || !name)
+		return -EINVAL;
+
+	err = zobj_register(&zstat->all_buffer_types, &zbuf->head,
+			    ZBUF, zbuf->owner, name);
+	if (err)
+		return err;
+	zbuf->zattr_set.n_std_attr = ZATTR_STD_NUM_ZBUF;
+	INIT_LIST_HEAD(&zbuf->list);
+	spin_lock_init(&zbuf->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(zio_register_buf);
+
+void zio_unregister_buf(struct zio_buffer_type *zbuf)
+{
+	if (!zbuf)
+		return;
+	zobj_unregister(&zstat->all_buffer_types, &zbuf->head);
+}
+EXPORT_SYMBOL(zio_unregister_buf);
+
+/* Register a trigger into the available trigger list */
+int zio_register_trig(struct zio_trigger_type *trig, const char *name)
+{
+	int err;
+
+	if (!trig || !name)
+		return -EINVAL;
+	err = zobj_register(&zstat->all_trigger_types, &trig->head,
+			    ZTRIG, trig->owner, name);
+	if (err)
+		return err;
+	trig->zattr_set.n_std_attr = ZATTR_STD_NUM_TRIG;
+	INIT_LIST_HEAD(&trig->list);
+	spin_lock_init(&trig->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(zio_register_trig);
+
+void zio_unregister_trig(struct zio_trigger_type *trig)
+{
+	if (!trig)
+		return;
+	zobj_unregister(&zstat->all_trigger_types, &trig->head);
+}
+EXPORT_SYMBOL(zio_unregister_trig);
+
+/* Initialize a list of objects */
+static int zlist_register(struct zio_object_list *zlist,
+			  struct kobject *parent,
+			  enum zio_object_type type,
+			  const char *name)
+{
+	int err = 0;
+
+	/* Create a defaul kobject for the list and add it to sysfs */
+	zlist->kobj = kobject_create_and_add(name, parent);
+	if (!zlist->kobj)
+		goto out_kobj;
+	pr_debug("%s:%d\n", __func__, __LINE__);
+
+	/* Initialize the specific list */
+	INIT_LIST_HEAD(&zlist->list);
+	zlist->zobj_type = type;
+	return 0;
+
+out_kobj:
+	kobject_put(zlist->kobj); /* we must _put even if it returned error */
+	return err;
+}
+/* Remove a list of objects */
+static void zlist_unregister(struct zio_object_list *zlist)
+{
+	kobject_del(zlist->kobj);
+	kobject_put(zlist->kobj);
+}
+
+static int __init zio_init(void)
+{
+	int err;
+
+	/* Some compile-time checks, so developers are free to hack around */
+	BUILD_BUG_ON_NOT_POWER_OF_2(ZIO_CHAN_MAXNUM);
+	BUILD_BUG_ON_NOT_POWER_OF_2(ZIO_CSET_MAXNUM);
+	BUILD_BUG_ON(ZIO_CSET_MAXNUM * ZIO_CHAN_MAXNUM * 2 > MINORMASK);
+	BUILD_BUG_ON(ZATTR_STD_NUM_ZDEV != ARRAY_SIZE(zio_zdev_attr_names));
+	BUILD_BUG_ON(ZATTR_STD_NUM_ZBUF != ARRAY_SIZE(zio_zbuf_attr_names));
+	BUILD_BUG_ON(ZATTR_STD_NUM_TRIG != ARRAY_SIZE(zio_trig_attr_names));
+
+	/* Initialize char device */
+	err = __zio_register_cdev();
+	if (err)
+		goto out_cdev;
+
+	/* Create the zio container */
+	zstat->kobj = kobject_create_and_add("zio", NULL);
+	if (!zstat->kobj)
+		goto out_kobj;
+
+	/* Register the three object lists (device, buffer and trigger) */
+	zlist_register(&zstat->all_devices, zstat->kobj, ZDEV,
+			"devices");
+	zlist_register(&zstat->all_trigger_types, zstat->kobj, ZTRIG,
+			"triggers");
+	zlist_register(&zstat->all_buffer_types, zstat->kobj, ZBUF,
+			"buffers");
+	pr_info("zio-core had been loaded\n");
+	return 0;
+
+out_kobj:
+	__zio_unregister_cdev();
+out_cdev:
+	return err;
+}
+
+static void __exit zio_exit(void)
+{
+	/* Remove the three object lists*/
+	zlist_unregister(&zstat->all_devices);
+	zlist_unregister(&zstat->all_buffer_types);
+	zlist_unregister(&zstat->all_trigger_types);
+
+	/* Remove from sysfs */
+	kobject_del(zstat->kobj);
+	kobject_put(zstat->kobj);
+
+	/* Remove char device */
+	__zio_unregister_cdev();
+
+	pr_info("zio-core had been unloaded\n");
+	return;
+}
+
+subsys_initcall(zio_init);
+module_exit(zio_exit);
+
+MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
+MODULE_DESCRIPTION("ZIO - ZIO Input Output");
+MODULE_LICENSE("GPL");
-- 
1.7.7.2

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 4/7] drivers/zio: add triggers and buffers
  2011-11-26 17:30 [RFC PATCH 0/7] Introducing ZIO, a new I/O framework Alessandro Rubini
                   ` (2 preceding siblings ...)
  2011-11-26 17:30 ` [RFC PATCH 3/7] drivers/zio: core files for the ZIO input/output Alessandro Rubini
@ 2011-11-26 17:30 ` Alessandro Rubini
  2011-11-26 17:31 ` [RFC PATCH 5/7] drivers/zio: add the zio-zero device driver Alessandro Rubini
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 25+ messages in thread
From: Alessandro Rubini @ 2011-11-26 17:30 UTC (permalink / raw)
  To: linux-iio, greg, linux-kernel
  Cc: federico.vaga, dcobas, siglesia, manohar.vanga

This adds two triggers and one buffer.
The files match commit 7d37663 in git://ohwr.org/misc/zio.git .

Signed-off-by: Alessandro Rubini <rubini@gnudd.com>
Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
Acked-by: Juan David Gonzalez Cobas <dcobas@cern.ch>
Acked-by: Samuel Iglesias Gonsalvez <siglesia@cern.ch>
Acked-by: Manohar Vanga <manohar.vanga@cern.ch>
---
 drivers/zio/buffers/Makefile          |    1 +
 drivers/zio/buffers/zio-buf-kmalloc.c |  273 +++++++++++++++++++++++++++++++++
 drivers/zio/triggers/Makefile         |    2 +
 drivers/zio/triggers/zio-trig-irq.c   |  203 ++++++++++++++++++++++++
 drivers/zio/triggers/zio-trig-timer.c |  193 +++++++++++++++++++++++
 5 files changed, 672 insertions(+), 0 deletions(-)
 create mode 100644 drivers/zio/buffers/Makefile
 create mode 100644 drivers/zio/buffers/zio-buf-kmalloc.c
 create mode 100644 drivers/zio/triggers/Makefile
 create mode 100644 drivers/zio/triggers/zio-trig-irq.c
 create mode 100644 drivers/zio/triggers/zio-trig-timer.c

diff --git a/drivers/zio/buffers/Makefile b/drivers/zio/buffers/Makefile
new file mode 100644
index 0000000..34b2f85
--- /dev/null
+++ b/drivers/zio/buffers/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ZIO) += zio-buf-kmalloc.o
diff --git a/drivers/zio/buffers/zio-buf-kmalloc.c b/drivers/zio/buffers/zio-buf-kmalloc.c
new file mode 100644
index 0000000..857c044
--- /dev/null
+++ b/drivers/zio/buffers/zio-buf-kmalloc.c
@@ -0,0 +1,273 @@
+/* Alessandro Rubini for CERN, 2011, GNU GPLv2 or later */
+
+/*
+ * This is a kmalloc-based buffer for the ZIO framework. It is used both
+ * as a default when no buffer is selected by applications and as an
+ * example about our our structures and methods are used.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+#include <linux/zio.h>
+#include <linux/zio-buffer.h>
+#include <linux/zio-trigger.h>
+
+/* This is an instance of a buffer, associated to two cdevs */
+struct zbk_instance {
+	struct zio_bi bi;
+	int nitem;
+	struct list_head list; /* items list and lock */
+	struct spinlock lock;
+};
+#define to_zbki(bi) container_of(bi, struct zbk_instance, bi)
+
+/* The list in the structure above collects a bunch of these */
+struct zbk_item {
+	struct zio_block block;
+	struct list_head list;	/* item list */
+	struct zbk_instance *instance;
+};
+#define to_item(block) container_of(block, struct zbk_item, block);
+
+static DEFINE_ZATTR_STD(ZBUF, zbk_std_zattr) = {
+	ZATTR_REG(zbuf, ZATTR_ZBUF_MAXLEN, S_IRUGO | S_IWUGO, 0x0, 16),
+};
+
+int kmalloc_conf_set(struct kobject *kobj, struct zio_attribute *zattr,
+		uint32_t  usr_val)
+{
+	zattr->value = usr_val;
+	return 0;
+}
+struct zio_sys_operations zbk_sysfs_ops = {
+	.conf_set = kmalloc_conf_set,
+};
+
+
+/* Alloc is called by the trigger (for input) or by f->write (for output) */
+static struct zio_block *zbk_alloc_block(struct zio_bi *bi,
+					 struct zio_control *ctrl,
+					 size_t datalen, gfp_t gfp)
+{
+	struct zbk_instance *zbki = to_zbki(bi);
+	struct zbk_item *item;
+	void *data;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+
+	/* alloc item and data. Control remains null at this point */
+	item = kzalloc(sizeof(*item), gfp);
+	data = kmalloc(datalen, gfp);
+	if (!item || !data)
+		goto out_free;
+	item->block.data = data;
+	item->block.datalen = datalen;
+	item->instance = zbki;
+
+	zio_set_ctrl(&item->block, ctrl);
+
+	return &item->block;
+
+out_free:
+	kfree(data);
+	kfree(item);
+	return ERR_PTR(-ENOMEM);
+}
+
+/* Free is called by f->read (for input) or by the trigger (for output) */
+static void zbk_free_block(struct zio_bi *bi, struct zio_block *block)
+{
+	struct zbk_item *item;
+	struct zbk_instance *zbki;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+
+	item = to_item(block);
+	zbki = item->instance;
+	kfree(block->data);
+	zio_free_control(zio_get_ctrl(block));
+	kfree(item);
+}
+
+/* When write() stores the first block, we try pushing it */
+static inline int __try_push(struct zio_ti *ti, struct zio_channel *chan,
+			     struct zio_block *block)
+{
+	if (ti->t_op->push_block(ti, chan, block) < 0)
+		return 0;
+	return 1;
+}
+
+/* Store is called by the trigger (for input) or by f->write (for output) */
+static int zbk_store_block(struct zio_bi *bi, struct zio_block *block)
+{
+	struct zbk_instance *zbki = to_zbki(bi);
+	struct zio_channel *chan = bi->chan;
+	struct zbk_item *item;
+	int awake = 0, pushed = 0, output;
+
+	pr_debug("%s:%d (%p, %p)\n", __func__, __LINE__, bi, block);
+
+	if (unlikely(!zio_get_ctrl(block))) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	item = to_item(block);
+	output = (bi->flags & ZIO_DIR) == ZIO_DIR_OUTPUT;
+
+	/* add to the buffer instance or push to the trigger */
+	spin_lock(&zbki->lock);
+	if (zbki->nitem == bi->zattr_set.std_zattr[ZATTR_ZBUF_MAXLEN].value)
+		goto out_unlock;
+	if (!zbki->nitem) {
+		if (unlikely(output))
+			pushed = __try_push(chan->cset->ti, chan, block);
+		else
+			awake = 1;
+	}
+	if (likely(!pushed)) {
+		zbki->nitem++;
+		list_add_tail(&item->list, &zbki->list);
+	}
+	spin_unlock(&zbki->lock);
+
+	/* if input, awake user space */
+	if (awake && ((bi->flags & ZIO_DIR) == ZIO_DIR_INPUT))
+		wake_up_interruptible(&bi->q);
+	return 0;
+
+out_unlock:
+	spin_unlock(&zbki->lock);
+	return -ENOSPC;
+}
+
+/* Retr is called by f->read (for input) or by the trigger (for output) */
+static struct zio_block *zbk_retr_block(struct zio_bi *bi)
+{
+	struct zbk_item *item;
+	struct zbk_instance *zbki;
+	struct zio_ti *ti;
+	struct list_head *first;
+	int awake = 0;
+
+	zbki = to_zbki(bi);
+
+	spin_lock(&zbki->lock);
+	if (list_empty(&zbki->list))
+		goto out_unlock;
+	first = zbki->list.next;
+	item = list_entry(first, struct zbk_item, list);
+	list_del(&item->list);
+	if (zbki->nitem == bi->zattr_set.std_zattr[ZATTR_ZBUF_MAXLEN].value)
+		awake = 1;
+	zbki->nitem--;
+	spin_unlock(&zbki->lock);
+
+	if (awake && ((bi->flags & ZIO_DIR) == ZIO_DIR_OUTPUT))
+		wake_up_interruptible(&bi->q);
+	pr_debug("%s:%d (%p, %p)\n", __func__, __LINE__, bi, item);
+	return &item->block;
+
+out_unlock:
+	spin_unlock(&zbki->lock);
+	/* There is no data in buffer, and we may pull to have data soon */
+	ti = bi->cset->ti;
+	if (ti->t_op->pull_block)
+		ti->t_op->pull_block(ti, bi->chan);
+	pr_debug("%s:%d (%p, %p)\n", __func__, __LINE__, bi, NULL);
+	return NULL;
+}
+
+/* Create is called by zio for each channel electing to use this buffer type */
+static struct zio_bi *zbk_create(struct zio_buffer_type *zbuf,
+	struct zio_channel *chan, fmode_t f_flags)
+{
+	struct zbk_instance *zbki;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+
+	zbki = kzalloc(sizeof(*zbki), GFP_KERNEL);
+	if (!zbki)
+		return ERR_PTR(-ENOMEM);
+	spin_lock_init(&zbki->lock);
+	INIT_LIST_HEAD(&zbki->list);
+
+	/* all the fields of zio_bi are initialied by the caller */
+	return &zbki->bi;
+}
+
+/* destroy is called by zio on channel removal or if it changes buffer type */
+static void zbk_destroy(struct zio_bi *bi)
+{
+	struct zbk_instance *zbki = to_zbki(bi);
+	struct zbk_item *item;
+	struct list_head *pos, *tmp;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+
+	/* no need to lock here, zio ensures we are not active */
+	list_for_each_safe(pos, tmp, &zbki->list) {
+		item = list_entry(pos, struct zbk_item, list);
+		zbk_free_block(&zbki->bi, &item->block);
+	}
+	kfree(zbki);
+}
+
+static const struct zio_buffer_operations zbk_buffer_ops = {
+	.alloc_block =	zbk_alloc_block,
+	.free_block =	zbk_free_block,
+	.store_block =	zbk_store_block,
+	.retr_block =	zbk_retr_block,
+	.create =	zbk_create,
+	.destroy =	zbk_destroy,
+};
+
+/*
+ * File operations. We only have read and write: mmap is definitely
+ * not suitable here, and open/release are not needed.
+ */
+
+static const struct file_operations zbk_file_ops = {
+	.owner =	THIS_MODULE,
+	.read =		zio_generic_read,
+	.write =	zio_generic_write,
+	.poll =		zio_generic_poll,
+	.release =	zio_generic_release,
+};
+
+static struct zio_buffer_type zbk_buffer = {
+	.owner =	THIS_MODULE,
+	.zattr_set = {
+		.std_zattr = zbk_std_zattr,
+	},
+	.s_op = &zbk_sysfs_ops,
+	.b_op = &zbk_buffer_ops,
+	.f_op = &zbk_file_ops,
+};
+
+static int zbk_init(void)
+{
+	return zio_register_buf(&zbk_buffer, "kmalloc");
+}
+
+static void zbk_exit(void)
+{
+	zio_unregister_buf(&zbk_buffer);
+	/* FIXME REMOVE all instances left */
+}
+
+module_init(zbk_init);
+module_exit(zbk_exit);
+MODULE_AUTHOR("Alessandro Rubini");
+MODULE_LICENSE("GPL");
diff --git a/drivers/zio/triggers/Makefile b/drivers/zio/triggers/Makefile
new file mode 100644
index 0000000..8e24b00
--- /dev/null
+++ b/drivers/zio/triggers/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ZIO) += zio-trig-timer.o
+obj-$(CONFIG_ZIO) += zio-trig-irq.o
diff --git a/drivers/zio/triggers/zio-trig-irq.c b/drivers/zio/triggers/zio-trig-irq.c
new file mode 100644
index 0000000..ff808cd
--- /dev/null
+++ b/drivers/zio/triggers/zio-trig-irq.c
@@ -0,0 +1,203 @@
+/* Alessandro Rubini for CERN, 2011, GNU GPLv2 or later */
+
+/*
+ * This is a trigger based on an external IRQ. You can specify the IRQ
+ * number or the GPIO number -- then the associated IRQ is used
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+
+#include <linux/zio.h>
+#include <linux/zio-sysfs.h>
+#include <linux/zio-buffer.h>
+#include <linux/zio-trigger.h>
+
+static int zti_irq = -1;
+static int zti_gpio = -1;
+module_param_named(irq, zti_irq, int, 0444);
+module_param_named(gpio, zti_gpio, int, 0444);
+
+enum zti_attrs {
+	ZTI_ATTR_NSAMPLES = 0,
+	ZTI_ATTR_IRQ,
+	ZTI_ATTR_GPIO,
+};
+
+static DEFINE_ZATTR_STD(TRIG, zti_std_attr) = {
+	ZATTR_REG(trig, ZATTR_TRIG_NSAMPLES, S_IRUGO | S_IWUGO,
+		  ZTI_ATTR_NSAMPLES, 16),
+};
+
+static struct zio_attribute zti_ext_attr[] = {
+	ZATTR_EXT_REG("irq", S_IRUGO, ZTI_ATTR_IRQ, -1),
+	ZATTR_EXT_REG("gpio", S_IRUGO, ZTI_ATTR_GPIO, -1),
+};
+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;
+}
+
+struct zio_sys_operations zti_s_ops = {
+	.conf_set = zti_conf_set,
+};
+
+irqreturn_t zti_handler(int irq, void *dev_id)
+{
+	struct zio_ti *ti = dev_id;
+
+	/* When a trigger fires, we must prepare our control and timestamp */
+	getnstimeofday(&ti->tstamp);
+	zio_fire_trigger(ti);
+	return IRQ_HANDLED;
+}
+
+/*
+ * The trigger operations are the core of a trigger type
+ */
+static int zti_push_block(struct zio_ti *ti, struct zio_channel *chan,
+			  struct zio_block *block)
+{
+	/* software triggers must store pending stuff in chan->t_priv */
+	pr_debug("%s:%d\n", __func__, __LINE__);
+
+	if (chan->active_block)
+		return -EBUSY;
+	chan->active_block = block;
+	return 0;
+}
+
+static int zti_config(struct zio_ti *ti, struct zio_control *ctrl)
+{
+	/* FIXME: config is not supported yet */
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	return 0;
+}
+
+static struct zio_ti *zti_create(struct zio_trigger_type *trig,
+				 struct zio_cset *cset,
+				 struct zio_control *ctrl, fmode_t flags)
+{
+	struct zio_ti *ti;
+
+	int ret;
+	pr_debug("%s:%d\n", __func__, __LINE__);
+
+	ti = kzalloc(sizeof(*ti), GFP_KERNEL);
+	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);
+	if (ret < 0) {
+		kfree(ti);
+		return ERR_PTR(ret);
+	}
+	return ti;
+}
+
+static void zti_destroy(struct zio_ti *ti)
+{
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	free_irq(zti_irq, &ti);
+	kfree(ti);
+}
+
+static const struct zio_trigger_operations zti_trigger_ops = {
+	.push_block = zti_push_block,
+	.pull_block = NULL,
+	.data_done = zio_generic_data_done,
+	.config = zti_config,
+	.create = zti_create,
+	.destroy = zti_destroy,
+};
+
+static struct zio_trigger_type zti_trigger = {
+	.owner = THIS_MODULE,
+	.zattr_set = {
+		.std_zattr = zti_std_attr,
+		.ext_zattr = zti_ext_attr,
+		.n_ext_attr = ARRAY_SIZE(zti_ext_attr),
+	},
+	.s_op = &zti_s_ops,
+	.t_op = &zti_trigger_ops,
+	.f_op = NULL, /* we use buffer fops */
+};
+
+/*
+ * A validation function, called at insmod and at parameter change
+ */
+static int zti_validate(int irq, int gpio)
+{
+	int ret = 0;
+
+	if (irq != -1 && gpio != -1) {
+		pr_err("%s: only set irq or gpio, not both\n", KBUILD_MODNAME);
+		return -EINVAL;
+	}
+	if (irq == -1 && gpio == -1) {
+		pr_err("%s: please set irq or gpio\n", KBUILD_MODNAME);
+		return -EINVAL;
+	}
+	if (gpio != -1) {
+		irq = gpio_to_irq(gpio);
+		if (irq >= 0)
+			ret  = gpio_request(gpio, KBUILD_MODNAME);
+		else
+			ret = irq;
+	}
+	if (ret < 0) {
+		pr_err("%s: invalid irq/gpio (%i/%i)\n", KBUILD_MODNAME,
+		       gpio, irq);
+		return ret;
+	}
+	zti_irq = irq; /* used at trigger_create time */
+	return 0;
+}
+
+/*
+ * init and exit
+ */
+static int __init zti_init(void)
+{
+	int ret = zti_validate(zti_irq, zti_gpio);
+	if (ret)
+		return ret;
+	return zio_register_trig(&zti_trigger, "irq");
+}
+
+static void __exit zti_exit(void)
+{
+	zio_unregister_trig(&zti_trigger);
+	if (zti_gpio)
+		gpio_free(zti_gpio);
+}
+
+module_init(zti_init);
+module_exit(zti_exit);
+MODULE_AUTHOR("Alessandro Rubini");
+MODULE_LICENSE("GPL");
diff --git a/drivers/zio/triggers/zio-trig-timer.c b/drivers/zio/triggers/zio-trig-timer.c
new file mode 100644
index 0000000..c429ecc
--- /dev/null
+++ b/drivers/zio/triggers/zio-trig-timer.c
@@ -0,0 +1,193 @@
+/* Alessandro Rubini for CERN, 2011, GNU GPLv2 or later */
+
+/*
+ * This is a timer-based trigger for the ZIO framework. It is not
+ * specific to a low-level device (every device can use it) and clearly
+ * multi-instance.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+
+#include <linux/zio.h>
+#include <linux/zio-sysfs.h>
+#include <linux/zio-buffer.h>
+#include <linux/zio-trigger.h>
+
+struct ztt_instance {
+	struct zio_ti ti;
+	struct timer_list timer;
+	unsigned long next_run;
+	unsigned long period;
+};
+#define to_ztt_instance(ti) container_of(ti, struct ztt_instance, ti);
+
+enum zti_attrs { /* names for the "addr" value of sw parameters */
+	ZTT_ATTR_NSAMPLES = 0,
+	ZTT_ATTR_PERIOD,
+};
+
+static DEFINE_ZATTR_STD(TRIG, ztt_std_attr) = {
+	ZATTR_REG(trig, ZATTR_TRIG_NSAMPLES, S_IRUGO | S_IWUGO,
+		  ZTT_ATTR_NSAMPLES, 16),
+};
+
+static struct zio_attribute ztt_ext_attr[] = {
+	ZATTR_EXT_REG("ms-period", S_IRUGO | S_IWUGO,
+		      ZTT_ATTR_PERIOD, 2000),
+};
+int ztt_conf_set(struct kobject *kobj, struct zio_attribute *zattr,
+		uint32_t  usr_val)
+{
+	struct zio_ti *ti = to_zio_ti(kobj);
+	struct ztt_instance *ztt;
+
+	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);
+	default:
+		pr_err("%s: unknown \"addr\" for configuration\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+struct zio_sys_operations ztt_s_ops = {
+	.conf_set = ztt_conf_set,
+};
+
+/* This runs when the timer expires */
+static void ztt_fn(unsigned long arg)
+{
+	struct zio_ti *ti = (void *)arg;
+	struct ztt_instance *ztt_instance;
+
+	/* When a trigger fires, we must prepare our control and timestamp */
+	getnstimeofday(&ti->tstamp);
+	/* FIXME: where is the jiffi count placed? */
+
+	ztt_instance = to_ztt_instance(ti);
+	zio_fire_trigger(ti);
+
+	if (!ztt_instance->period)
+		return; /* one-shot */
+
+	ztt_instance = to_ztt_instance(ti)
+	ztt_instance->next_run += ztt_instance->period;
+	mod_timer(&ztt_instance->timer, ztt_instance->next_run);
+}
+
+/*
+ * The trigger operations are the core of a trigger type
+ */
+static int ztt_push_block(struct zio_ti *ti, struct zio_channel *chan,
+			  struct zio_block *block)
+{
+	/* software triggers must store pending stuff in chan->t_priv */
+	pr_debug("%s:%d\n", __func__, __LINE__);
+
+	if (chan->active_block)
+		return -EBUSY;
+	chan->active_block = block;
+	return 0;
+}
+
+static int ztt_config(struct zio_ti *ti, struct zio_control *ctrl)
+{
+	/* FIXME: config is not supported yet */
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	return 0;
+}
+
+static struct zio_ti *ztt_create(struct zio_trigger_type *trig,
+				 struct zio_cset *cset,
+				 struct zio_control *ctrl, fmode_t flags)
+{
+	struct ztt_instance *ztt_instance;
+	struct zio_ti *ti;
+	uint32_t ms;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+
+	ztt_instance = kzalloc(sizeof(struct ztt_instance), GFP_KERNEL);
+	if (!ztt_instance)
+		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));
+	ztt_instance->next_run = jiffies + HZ;
+	ms = ztt_ext_attr[0].value;
+	ztt_instance->period = msecs_to_jiffies(ms); /* module param */
+
+	/* Start the timer (dangerous: ti is not filled) */
+	mod_timer(&ztt_instance->timer, ztt_instance->next_run);
+
+	return ti;
+}
+
+static void ztt_destroy(struct zio_ti *ti)
+{
+	struct ztt_instance *ztt_instance;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+	ztt_instance = to_ztt_instance(ti);
+	del_timer_sync(&ztt_instance->timer);
+	kfree(ti);
+}
+
+static const struct zio_trigger_operations ztt_trigger_ops = {
+	.push_block = ztt_push_block,
+	.pull_block = NULL,
+	.data_done = zio_generic_data_done,
+	.config = ztt_config,
+	.create = ztt_create,
+	.destroy = ztt_destroy,
+};
+
+static struct zio_trigger_type ztt_trigger = {
+	.owner = THIS_MODULE,
+	.zattr_set = {
+		.std_zattr = ztt_std_attr,
+		.ext_zattr = ztt_ext_attr,
+		.n_ext_attr = ARRAY_SIZE(ztt_ext_attr),
+	},
+	.s_op = &ztt_s_ops,
+	.t_op = &ztt_trigger_ops,
+	.f_op = NULL, /* we use buffer fops */
+};
+
+/*
+ * init and exit
+ */
+static int __init ztt_init(void)
+{
+	return zio_register_trig(&ztt_trigger, "timer");
+}
+
+static void __exit ztt_exit(void)
+{
+	zio_unregister_trig(&ztt_trigger);
+}
+
+module_init(ztt_init);
+module_exit(ztt_exit);
+MODULE_AUTHOR("Alessandro Rubini");
+MODULE_LICENSE("GPL");
-- 
1.7.7.2

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 5/7] drivers/zio: add the zio-zero device driver
  2011-11-26 17:30 [RFC PATCH 0/7] Introducing ZIO, a new I/O framework Alessandro Rubini
                   ` (3 preceding siblings ...)
  2011-11-26 17:30 ` [RFC PATCH 4/7] drivers/zio: add triggers and buffers Alessandro Rubini
@ 2011-11-26 17:31 ` Alessandro Rubini
  2011-11-26 17:31 ` [RFC PATCH 6/7] drivers/zio: add user-space tool zio-dump Alessandro Rubini
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 25+ messages in thread
From: Alessandro Rubini @ 2011-11-26 17:31 UTC (permalink / raw)
  To: linux-iio, greg, linux-kernel
  Cc: federico.vaga, dcobas, siglesia, manohar.vanga

From: Federico Vaga <federico.vaga@gmail.com>

zio-zero is a demonstration driver that generates /dev/zero-like data.
I can be used to test the default trigger and the default buffer.
The files match commit 7d37663 in git://ohwr.org/misc/zio.git .

Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
Signed-off-by: Alessandro Rubini <rubini@gnudd.com>
Acked-by: Juan David Gonzalez Cobas <dcobas@cern.ch>
Acked-by: Samuel Iglesias Gonsalvez <siglesia@cern.ch>
Acked-by: Manohar Vanga <manohar.vanga@cern.ch>
---
 drivers/zio/drivers/Makefile   |    1 +
 drivers/zio/drivers/zio-zero.c |   87 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 88 insertions(+), 0 deletions(-)
 create mode 100644 drivers/zio/drivers/Makefile
 create mode 100644 drivers/zio/drivers/zio-zero.c

diff --git a/drivers/zio/drivers/Makefile b/drivers/zio/drivers/Makefile
new file mode 100644
index 0000000..d59387b
--- /dev/null
+++ b/drivers/zio/drivers/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ZIO) += zio-zero.o
diff --git a/drivers/zio/drivers/zio-zero.c b/drivers/zio/drivers/zio-zero.c
new file mode 100644
index 0000000..f803e09
--- /dev/null
+++ b/drivers/zio/drivers/zio-zero.c
@@ -0,0 +1,87 @@
+/* Federico Vaga for CERN, 2011, GNU GPLv2 or later */
+/*
+ * zero-zio is a simple zio driver which fill buffer with 0. From the ZIO
+ * point of view is an input device
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+
+#include <linux/zio.h>
+#include <linux/zio-buffer.h>
+
+static char *zzero_trigger;
+static char *zzero_buffer;
+module_param_named(trigger, zzero_trigger, charp, 0444);
+module_param_named(buffer, zzero_buffer, charp, 0444);
+
+static int zzero_input(struct zio_cset *cset)
+{
+	struct zio_channel *chan;
+	struct zio_block *block;
+	static uint8_t datum;
+	uint8_t *data;
+	int i;
+
+	/* Return immediately: just fill the blocks */
+	cset_for_each(cset, chan) {
+		block = chan->active_block;
+		if (!block)
+			continue;
+		switch (chan->index) {
+		case 0: /* zero */
+			memset(block->data, 0x0, block->datalen);
+			break;
+		case 1: /* random */
+			get_random_bytes(block->data, block->datalen);
+			break;
+		case 2: /* sequence */
+			data = block->data;
+			for (i = 0; i < block->datalen; i++)
+				data[i] = datum++;
+		}
+	}
+	return 1; /* Already done */
+}
+
+static const struct zio_device_operations zzero_d_op = {
+	.input_cset =		zzero_input,
+};
+
+static struct zio_cset zzero_cset[] = {
+	{
+		.n_chan =	3,
+		.ssize =	1,
+		.flags =	ZIO_DIR_INPUT | ZCSET_TYPE_ANALOG,
+	},
+};
+
+static struct zio_device zzero_dev = {
+	.owner =		THIS_MODULE,
+	.d_op =			&zzero_d_op,
+	.cset =			zzero_cset,
+	.n_cset =		ARRAY_SIZE(zzero_cset),
+};
+
+static int __init zzero_init(void)
+{
+	if (zzero_trigger)
+		zzero_dev.preferred_trigger = zzero_trigger;
+	if (zzero_buffer)
+		zzero_dev.preferred_buffer = zzero_buffer;
+	return zio_register_dev(&zzero_dev, "zzero");
+}
+
+static void __exit zzero_exit(void)
+{
+	zio_unregister_dev(&zzero_dev);
+}
+
+module_init(zzero_init);
+module_exit(zzero_exit);
+
+MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
+MODULE_DESCRIPTION("A zio driver which fakes zero, random and sawtooth input");
+MODULE_LICENSE("GPL");
-- 
1.7.7.2

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 6/7] drivers/zio: add user-space tool zio-dump
  2011-11-26 17:30 [RFC PATCH 0/7] Introducing ZIO, a new I/O framework Alessandro Rubini
                   ` (4 preceding siblings ...)
  2011-11-26 17:31 ` [RFC PATCH 5/7] drivers/zio: add the zio-zero device driver Alessandro Rubini
@ 2011-11-26 17:31 ` Alessandro Rubini
  2011-11-26 17:31 ` [RFC PATCH 7/7] zio: insert in Kbuild so it is actually compiled Alessandro Rubini
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 25+ messages in thread
From: Alessandro Rubini @ 2011-11-26 17:31 UTC (permalink / raw)
  To: linux-iio, greg, linux-kernel
  Cc: federico.vaga, dcobas, siglesia, manohar.vanga

Use of zio-dump is described in the README.
The files match commit 7d37663 in git://ohwr.org/misc/zio.git .

Signed-off-by: Alessandro Rubini <rubini@gnudd.com>
Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
Acked-by: Juan David Gonzalez Cobas <dcobas@cern.ch>
Acked-by: Samuel Iglesias Gonsalvez <siglesia@cern.ch>
Acked-by: Manohar Vanga <manohar.vanga@cern.ch>
---
 drivers/zio/zio-dump.c |  196 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 196 insertions(+), 0 deletions(-)
 create mode 100644 drivers/zio/zio-dump.c

diff --git a/drivers/zio/zio-dump.c b/drivers/zio/zio-dump.c
new file mode 100644
index 0000000..e6f2149
--- /dev/null
+++ b/drivers/zio/zio-dump.c
@@ -0,0 +1,196 @@
+/*
+ * Trivial utility that reports data from ZIO input channels
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+
+#include <linux/zio.h>
+#include <linux/zio-buffer.h>
+
+unsigned char buf[1024*1024];
+char *prgname;
+
+void read_channel(int cfd, int dfd, FILE *log)
+{
+	int err = 0;
+	struct zio_control ctrl;
+	int i, j;
+
+	i = read(cfd, &ctrl, sizeof(ctrl));
+	switch (i) {
+	case -1:
+		fprintf(stderr, "%s: control read: %s\n",
+			prgname, strerror(errno));
+		exit(1);
+	case 0:
+		fprintf(stderr, "%s: control read: unexpected EOF\n",
+			prgname);
+		exit(1);
+	default:
+		fprintf(stderr, "%s: ctrl read: %i bytes (expected %i)\n",
+			prgname, i, sizeof(ctrl));
+		/* continue anyways */
+	case sizeof(ctrl):
+		break; /* ok */
+	}
+
+	/* Fail badly if the version is not the right one */
+	if (ctrl.major_version != ZIO_MAJOR_VERSION)
+		err++;
+	if (ZIO_MAJOR_VERSION == 0 && ctrl.minor_version != ZIO_MINOR_VERSION)
+		err++;
+	if (err) {
+		fprintf(stderr, "%s: kernel has zio %i.%i, "
+			"but I'm compiled for %i.%i\n", prgname,
+			ctrl.major_version, ctrl.minor_version,
+			ZIO_MAJOR_VERSION, ZIO_MINOR_VERSION);
+		exit(1);
+	}
+	if (ctrl.minor_version != ZIO_MINOR_VERSION) {
+		static int warned;
+
+		if (!warned++)
+			fprintf(stderr, "%s: warning: minor version mismatch\n",
+				prgname);
+	}
+
+	printf("Ctrl: version %i.%i, trigger %.16s, dev %.16s, "
+	       "cset %i, chan %i\n",
+	       ctrl.major_version, ctrl.minor_version,
+	       ctrl.triggername, ctrl.devname, ctrl.cset_i,
+	       ctrl.chan_i);
+	printf("Ctrl: seq %i, n %i, size %i, bits %i, "
+	       "flags %08x (%s)\n",
+	       ctrl.seq_num,
+	       ctrl.nsamples,
+	       ctrl.ssize,
+	       ctrl.sbits,
+	       ctrl.flags,
+	       ctrl.flags & ZIO_CONTROL_LITTLE_ENDIAN
+	       ? "little-endian" :
+	       ctrl.flags & ZIO_CONTROL_BIG_ENDIAN
+	       ? "big-endian" : "unknown-endian");
+	printf("Ctrl: stamp %lli.%09lli (%lli)\n",
+	       (long long)ctrl.tstamp.secs,
+	       (long long)ctrl.tstamp.ticks,
+	       (long long)ctrl.tstamp.bins);
+	/* FIXME: some control information is missing */
+
+	i = read(dfd, buf, sizeof(buf));
+	if (i < 0) {
+		fprintf(stderr, "%s: data read: %s\n",
+			prgname, strerror(errno));
+		return; /* next ctrl, let's see... */
+	}
+	if (!i) {
+		fprintf(stderr, "%s: data read: unexpected EOF\n", prgname);
+		return;
+	}
+	if (i != ctrl.nsamples * ctrl.ssize) {
+		if (i == sizeof(buf)) {
+			fprintf(stderr, "%s: buffer too small: "
+				"please fix me and recompile\n", prgname);
+			/* FIXME: empty the data channel */
+		} else {
+			fprintf(stderr, "%s: ctrl: read %i bytes "
+				"(exp %i)\n", prgname, i,
+				ctrl.nsamples * ctrl.ssize);
+		}
+		/* continue anyways */
+	}
+	fwrite(buf, 1, i, log);
+
+	/* report data to stdout */
+	for (j = 0; j < i; j++) {
+		if (!(j & 0xf))
+			printf("Data:");
+		printf(" %02x", buf[j]);
+		if ((j & 0xf) == 0xf || j == i - 1)
+			putchar('\n');
+	}
+	putchar('\n');
+}
+
+int main(int argc, char **argv)
+{
+	FILE *f;
+	char *outfname;
+	int *cfd; /* control file descriptors */
+	int *dfd; /* data file descriptors */
+	fd_set control_set, ready_set;
+	int i, j, maxfd, ndev;
+
+	if (argc < 3 || (argc & 1) != 1) {
+		fprintf(stderr, "%s: Wrong number of arguments\n"
+			"Use: \"%s <ctrl-file> <data-file> [...]\"\n",
+			argv[0], argv[0]);
+		exit(1);
+	}
+	prgname = argv[0];
+	cfd = malloc(argc / 2 * sizeof(*cfd));
+	dfd = malloc(argc / 2 * sizeof(*dfd));
+	if (!cfd || !dfd) {
+		fprintf(stderr, "%s: malloc: %s\n", prgname, strerror(errno));
+		exit(1);
+	}
+
+	/* Open all pairs, and build the fd_set for later select() */
+	FD_ZERO(&control_set);
+	for (i = 1, j = 0; i < argc; i += 2, j++) {
+		cfd[j] = open(argv[i], O_RDONLY);
+		dfd[j] = open(argv[i + 1], O_RDONLY);
+		if (cfd[j] < 0) {
+			fprintf(stderr, "%s: %s: %s\n", prgname, argv[i],
+				strerror(errno));
+			exit(1);
+		}
+		if (dfd[j] < 0) {
+			fprintf(stderr, "%s: %s: %s\n", prgname, argv[i + 1],
+				strerror(errno));
+			exit(1);
+		}
+		/* ctrl file is used in select, data file is non-blocking */
+		FD_SET(cfd[j], &control_set);
+		fcntl(dfd[j], F_SETFL, fcntl(dfd[j], F_GETFL) | O_NONBLOCK);
+		maxfd = dfd[j];
+	}
+	ndev = j;
+
+	/* always log data we read to some filename */
+	outfname = getenv("ZIO_DUMP_TO");
+	if (!outfname)
+		outfname = "/dev/null";
+	f = fopen(outfname, "w");
+	if (!f) {
+		fprintf(stderr, "%s: %s: %s\n", prgname, outfname,
+			strerror(errno));
+		exit(1);
+	}
+	/* ensure proper strace information and output to pipes */
+	setlinebuf(stdout);
+	setbuf(f, NULL);
+
+	/* now read control and then data, forever */
+	while (1) {
+		ready_set = control_set;
+		i = select(maxfd + 1, &ready_set, NULL, NULL, NULL);
+		if (i < 0 && errno == EINTR)
+			continue;
+		if (i < 0) {
+			fprintf(stderr, "%s: select(): %s\n", prgname,
+				strerror(errno));
+			exit(1);
+		}
+		for (j = 0; j < ndev; j++)
+			if (FD_ISSET(cfd[j], &ready_set))
+				read_channel(cfd[j], dfd[j], f);
+	}
+}
-- 
1.7.7.2

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 7/7] zio: insert in Kbuild so it is actually compiled
  2011-11-26 17:30 [RFC PATCH 0/7] Introducing ZIO, a new I/O framework Alessandro Rubini
                   ` (5 preceding siblings ...)
  2011-11-26 17:31 ` [RFC PATCH 6/7] drivers/zio: add user-space tool zio-dump Alessandro Rubini
@ 2011-11-26 17:31 ` Alessandro Rubini
  2011-11-26 18:09 ` [RFC PATCH 0/7] Introducing ZIO, a new I/O framework Lars-Peter Clausen
  2011-11-26 19:11 ` Alessandro Rubini
  8 siblings, 0 replies; 25+ messages in thread
From: Alessandro Rubini @ 2011-11-26 17:31 UTC (permalink / raw)
  To: linux-iio, greg, linux-kernel
  Cc: federico.vaga, dcobas, siglesia, manohar.vanga

Signed-off-by: Alessandro Rubini <rubini@gnudd.com>
Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
---
 drivers/Kconfig     |    2 ++
 drivers/Makefile    |    1 +
 drivers/zio/Kconfig |   12 ++++++++++++
 3 files changed, 15 insertions(+), 0 deletions(-)
 create mode 100644 drivers/zio/Kconfig

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 5289508..ef7bf06 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -118,6 +118,8 @@ source "drivers/vlynq/Kconfig"
 
 source "drivers/virtio/Kconfig"
 
+source "drivers/zio/Kconfig"
+
 source "drivers/xen/Kconfig"
 
 source "drivers/staging/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 91077ac..96da622 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -118,6 +118,7 @@ obj-$(CONFIG_SSB)		+= ssb/
 obj-$(CONFIG_BCMA)		+= bcma/
 obj-$(CONFIG_VHOST_NET)		+= vhost/
 obj-$(CONFIG_VLYNQ)		+= vlynq/
+obj-$(CONFIG_ZIO)		+= zio/
 obj-$(CONFIG_STAGING)		+= staging/
 obj-y				+= platform/
 obj-y				+= ieee802154/
diff --git a/drivers/zio/Kconfig b/drivers/zio/Kconfig
new file mode 100644
index 0000000..774a185
--- /dev/null
+++ b/drivers/zio/Kconfig
@@ -0,0 +1,12 @@
+
+config ZIO
+	tristate "The ZIO framework for high-bandwidth I/O"
+	help
+	  This is a new proposed framework for input/output, whose
+	  main use case is multi-megabyte per second I/O on several
+	  channels, with hardware timestamping and offline elaboration.
+
+	  Currently, all drivers (and triggers, and buffers) are compiled,
+	  with no Kconfig selection at a finer resolution.
+
+	  See www.ohwr.org/projects/zio for docs, slides, repo and list.
-- 
1.7.7.2

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 0/7] Introducing ZIO, a new I/O framework
  2011-11-26 17:30 [RFC PATCH 0/7] Introducing ZIO, a new I/O framework Alessandro Rubini
                   ` (6 preceding siblings ...)
  2011-11-26 17:31 ` [RFC PATCH 7/7] zio: insert in Kbuild so it is actually compiled Alessandro Rubini
@ 2011-11-26 18:09 ` Lars-Peter Clausen
  2011-11-26 19:11 ` Alessandro Rubini
  8 siblings, 0 replies; 25+ messages in thread
From: Lars-Peter Clausen @ 2011-11-26 18:09 UTC (permalink / raw)
  To: Alessandro Rubini
  Cc: linux-iio, greg, linux-kernel, federico.vaga, dcobas, siglesia,
	manohar.vanga

On 11/26/2011 06:30 PM, Alessandro Rubini wrote:
> This RFC patch-set introduces the ZIO framework for input/output,
> which will be used in the new series of drivers by the BE-CO-HT
> group at CERN.
> 
> The use-case it is meant to cover is very fast I/O with
> hardware-provided timestamps.  The first production driver we will
> support is a 100Ms/s 4-channel 14-bit ADC (developed on ohwr: see
> http://www.ohwr.org/projects/fmc-adc-100m14b4cha ).  We need similar
> bandwidth on output.
> 
> The synchronization engine of that FMC card and other ones is going to
> be White Rabbit (http://www.ohwr.org/projects/white-rabbit).
> 
> Currently, the patch-set includes one example driver (zio-zero)
> that behaves like /dev/zero and /dev/urandom. Other drivers will
> come soon, both demo and real hardware.
> 
> Slides for a tutorial on the design ideas are online here:
> http://www.ohwr.org/attachments/881/zio-111123.pdf
> 
> A list of pending issues and development plans is online at:
> http://www.ohwr.org/projects/zio/wiki/Todo

You've Cc'ed the IIO mailinglist, so you know about the IIO framework. Could
you explain why you need a new framework and your devices can't be supported by
the IIO framework? After a first quick glance ZIO looks to me like a subset of IIO.

- Lars

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 0/7] Introducing ZIO, a new I/O framework
  2011-11-26 17:30 [RFC PATCH 0/7] Introducing ZIO, a new I/O framework Alessandro Rubini
                   ` (7 preceding siblings ...)
  2011-11-26 18:09 ` [RFC PATCH 0/7] Introducing ZIO, a new I/O framework Lars-Peter Clausen
@ 2011-11-26 19:11 ` Alessandro Rubini
  2011-12-01 21:41   ` Linus Walleij
  8 siblings, 1 reply; 25+ messages in thread
From: Alessandro Rubini @ 2011-11-26 19:11 UTC (permalink / raw)
  To: lars
  Cc: linux-iio, greg, linux-kernel, federico.vaga, dcobas, siglesia,
	manohar.vanga

> You've Cc'ed the IIO mailinglist, so you know about the IIO
> framework.

Yes, we are aware of it. Initially we hoped to use it for our
boards. There is an analysis by Federico on the ohwr wiki:

http://www.ohwr.org/projects/zio/wiki/Iio

See especially the final table about how it fits our requirements:

http://www.ohwr.org/projects/zio/wiki/Requirements

> Could you explain why you need a new framework and your devices
> can't be supported by the IIO framework?

Mainly, because the use-cases it is designed for are different.  It
handles data one sample at a time while our data blocks are tens of
hundreds of megabytes; there is still no support for output; data is
expected to be analog only; timestamps are assumed to be nanoseconds.
Also, we need easy off-line elaboration of data, that's why we attach
a control structure to each data block (and user-space can ignore the
control structure and work with data alone, if needed).

ZIO can work with accelerometers (we have one we'll support soon),
but we need to support accelerators too.  I think IIO is much better
than ZIO for accelerometers, thermometers and similar stuff.

> After a first quick glance ZIO looks to me like a subset of IIO.

In some sense, yes. It's only a mechanism for data transfer, insisting
to not attach any meaning to the data it carries around.

I'm open to suggestions (_we_ are) about how to easily use IIO for
output, for hardware timestamps (we have 3 32-bit fields) and for very
large data blocks, with DMA to/from user space -- sure we don't have this
last point in ZIO at this point in time.

Thank you for your interest
/alessandro

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 1/7] Documentation: add docs for drivers/zio
  2011-11-26 17:30 ` [RFC PATCH 1/7] Documentation: add docs for drivers/zio Alessandro Rubini
@ 2011-11-26 20:00   ` Greg KH
  2011-11-26 21:48     ` Federico Vaga
  2011-11-26 22:16   ` Jonathan Cameron
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 25+ messages in thread
From: Greg KH @ 2011-11-26 20:00 UTC (permalink / raw)
  To: Alessandro Rubini
  Cc: linux-iio, linux-kernel, federico.vaga, dcobas, siglesia, manohar.vanga

On Sat, Nov 26, 2011 at 06:30:20PM +0100, Alessandro Rubini wrote:
> This is documentation for the beta3 release of zio.
> The files match commit 7d37663 in git://ohwr.org/misc/zio.git .
> 
> We are aware the "modules.txt" file is not correct as it lists files
> that are not ready. We decided to avoid fixing it for this RFC
> submission, which won't go upstream anyways.

I think you are using sysfs files here, yet I don't see any
Documentation/ABI files describing those sysfs files and how they are to
be used.  Could you please include them?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 2/7] include/linux: add headers for drivers/zio
  2011-11-26 17:30 ` [RFC PATCH 2/7] include/linux: add headers " Alessandro Rubini
@ 2011-11-26 20:02   ` Greg KH
  2011-11-26 21:46     ` Federico Vaga
  0 siblings, 1 reply; 25+ messages in thread
From: Greg KH @ 2011-11-26 20:02 UTC (permalink / raw)
  To: Alessandro Rubini
  Cc: linux-iio, linux-kernel, federico.vaga, dcobas, siglesia, manohar.vanga

On Sat, Nov 26, 2011 at 06:30:31PM +0100, Alessandro Rubini wrote:
> +/*
> + * We use the same functions to deal with attributes, but the structures
> + * we act on may be different (dev, cset, channel). Thus, all structures
> + * begin with the type identifier, and zio_obj_head is used in container_of
> + */

Because you are using container_of, you don't have to have the structure
at the beginning of the structure it is included in, right?

> +enum zio_object_type {
> +	ZNONE = 0,	/* reserved for non zio object */
> +	ZDEV, ZCSET, ZCHAN,
> +	ZTRIG, ZTI,	/* trigger and trigger instance */
> +	ZBUF, ZBI,	/* buffer and buffer instance */
> +};
> +
> +/* zio_obj_head is for internal use only, as explained above */
> +struct zio_obj_head {
> +	struct kobject		kobj;
> +	enum zio_object_type	zobj_type;
> +	char			name[ZIO_NAME_LEN];
> +};
> +#define to_zio_head(_kobj) container_of(_kobj, struct zio_obj_head, kobj)
> +#define to_zio_dev(_kobj) container_of(_kobj, struct zio_device, head.kobj)
> +#define to_zio_cset(_kobj) container_of(_kobj, struct zio_cset, head.kobj)
> +#define to_zio_chan(_kobj) container_of(_kobj, struct zio_channel, head.kobj)

Why are you using a "raw" kobject and not 'struct device' instead?  If
you use a kobject, you loose all of the device tree information that a
real struct device provides to userspace, and can only cause confusion
in the long run.

This also will provide you the "type" and name that you are needing
here, as well as lots of other good things (properly formatted logging
messages, uevents, etc.)

Please consider moving to that instead.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 3/7] drivers/zio: core files for the ZIO input/output
  2011-11-26 17:30 ` [RFC PATCH 3/7] drivers/zio: core files for the ZIO input/output Alessandro Rubini
@ 2011-11-26 20:03   ` Greg KH
  2011-11-26 22:58     ` Federico Vaga
  0 siblings, 1 reply; 25+ messages in thread
From: Greg KH @ 2011-11-26 20:03 UTC (permalink / raw)
  To: Alessandro Rubini
  Cc: linux-iio, linux-kernel, federico.vaga, dcobas, siglesia, manohar.vanga

On Sat, Nov 26, 2011 at 06:30:42PM +0100, Alessandro Rubini wrote:
> +static struct kobj_type zdktype = { /* For standard and extended attribute */
> +	.release   = NULL,

Sweet!

As-per the in-kernel documentation, I now get to mock you for doing
this :)

Please NEVER DO THIS, you are ignoring the messages that the kernel
sends you when you remove one of these devices, and causing a memory
leak.

Not nice at all, yet another reason to use a 'struct device'.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 2/7] include/linux: add headers for drivers/zio
  2011-11-26 20:02   ` Greg KH
@ 2011-11-26 21:46     ` Federico Vaga
  2011-11-27  9:32       ` Greg KH
  0 siblings, 1 reply; 25+ messages in thread
From: Federico Vaga @ 2011-11-26 21:46 UTC (permalink / raw)
  To: Greg KH
  Cc: Alessandro Rubini, linux-iio, linux-kernel, dcobas, siglesia,
	manohar.vanga

In data sabato 26 novembre 2011 12:02:16, Greg KH ha scritto:
> On Sat, Nov 26, 2011 at 06:30:31PM +0100, Alessandro Rubini wrote:
> > +/*
> > + * We use the same functions to deal with attributes, but the structures
> > + * we act on may be different (dev, cset, channel). Thus, all structures
> > + * begin with the type identifier, and zio_obj_head is used in
> > container_of + */
> 
> Because you are using container_of, you don't have to have the structure
> at the beginning of the structure it is included in, right?

Different structures have similar features and we use zio_obj_head->zobj_type to 
identify the correct container_of to apply.  Sometimes we use the head only, so 
we delay container_of later. 

> > +enum zio_object_type {
> > +   ZNONE = 0,      /* reserved for non zio object */
> > +   ZDEV, ZCSET, ZCHAN,
> > +   ZTRIG, ZTI,     /* trigger and trigger instance */
> > +   ZBUF, ZBI,      /* buffer and buffer instance */
> > +};
> > +
> > +/* zio_obj_head is for internal use only, as explained above */
> > +struct zio_obj_head {
> > +   struct kobject          kobj;
> > +   enum zio_object_type    zobj_type;
> > +   char                    name[ZIO_NAME_LEN];
> > +};
> > +#define to_zio_head(_kobj) container_of(_kobj, struct zio_obj_head, kobj)
> > +#define to_zio_dev(_kobj) container_of(_kobj, struct zio_device,
> > head.kobj) +#define to_zio_cset(_kobj) container_of(_kobj, struct
> > zio_cset, head.kobj) +#define to_zio_chan(_kobj) container_of(_kobj,
> > struct zio_channel, head.kobj)
> Why are you using a "raw" kobject and not 'struct device' instead? 

The device way was experimented and we can move in that direction. I also 
tried a mixed solution with device and kobject, because not all the zio objects 
can be device.

I decided to use the kobject way because it was an easier and flexible solution 
for a fast development.

> If you use a kobject, you loose all of the device tree information that a
> real struct device provides to userspace,

You mean the device sysfs tree? Acctually we don't need that information

> and can only cause confusion in the long run.

I think it can be confusing to declare a device what is not a device, for 
example: buffer, trigger, channel-set (maybe in some 
sense can be a device) and channel 

> This also will provide you the "type" and name that you are needing
> here, as well as lots of other good things (properly formatted logging
> messages, uevents, etc.)

If you refer to device_type, I think it is too complex for our purpose (also 
tried during the device "experiment"), we only need to recognize a zio object, 
we don't need al the stuff within device_type.

You are right, device is full of great things and the migration to device is 
always a point of discussion, but actually kobject meet well with our needs.

> Please consider moving to that instead.

We can re-evaluate and better explain the choice if kobj is still the 
preferrable one

> thanks,
> 
> greg k-h
-- 
Federico Vaga

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 1/7] Documentation: add docs for drivers/zio
  2011-11-26 20:00   ` Greg KH
@ 2011-11-26 21:48     ` Federico Vaga
  0 siblings, 0 replies; 25+ messages in thread
From: Federico Vaga @ 2011-11-26 21:48 UTC (permalink / raw)
  To: Greg KH
  Cc: Alessandro Rubini, linux-iio, linux-kernel, dcobas, siglesia,
	manohar.vanga

In data sabato 26 novembre 2011 12:00:12, Greg KH ha scritto:
> On Sat, Nov 26, 2011 at 06:30:20PM +0100, Alessandro Rubini wrote:
> > This is documentation for the beta3 release of zio.
> > The files match commit 7d37663 in git://ohwr.org/misc/zio.git .
> > 
> > We are aware the "modules.txt" file is not correct as it lists files
> > that are not ready. We decided to avoid fixing it for this RFC
> > submission, which won't go upstream anyways.
> 
> I think you are using sysfs files here, yet I don't see any
> Documentation/ABI files describing those sysfs files and how they are to
> be used.  Could you please include them?

Sure, we'll do for the next release.

> thanks,
> 
> greg k-h
-- 
Federico Vaga

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 1/7] Documentation: add docs for drivers/zio
  2011-11-26 17:30 ` [RFC PATCH 1/7] Documentation: add docs for drivers/zio Alessandro Rubini
  2011-11-26 20:00   ` Greg KH
@ 2011-11-26 22:16   ` Jonathan Cameron
  2011-11-26 22:53   ` Alessandro Rubini
  2011-12-06  5:12   ` Randy Dunlap
  3 siblings, 0 replies; 25+ messages in thread
From: Jonathan Cameron @ 2011-11-26 22:16 UTC (permalink / raw)
  To: Alessandro Rubini
  Cc: linux-iio, greg, linux-kernel, federico.vaga, dcobas, siglesia,
	manohar.vanga

On 11/26/2011 05:30 PM, Alessandro Rubini wrote:
> This is documentation for the beta3 release of zio.
> The files match commit 7d37663 in git://ohwr.org/misc/zio.git .
> 
> We are aware the "modules.txt" file is not correct as it lists files
> that are not ready. We decided to avoid fixing it for this RFC
> submission, which won't go upstream anyways.
> 
> Signed-off-by: Alessandro Rubini <rubini@gnudd.com>
> Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
> Acked-by: Juan David Gonzalez Cobas <dcobas@cern.ch>
> Acked-by: Samuel Iglesias Gonsalvez <siglesia@cern.ch>
> Acked-by: Manohar Vanga <manohar.vanga@cern.ch>
> ---
>  Documentation/zio/00-INDEX    |   10 +++
>  Documentation/zio/buffer.txt  |  114 ++++++++++++++++++++++++++++++++++++
>  Documentation/zio/device.txt  |   69 ++++++++++++++++++++++
>  Documentation/zio/modules.txt |   45 ++++++++++++++
>  Documentation/zio/trigger.txt |  128 +++++++++++++++++++++++++++++++++++++++++
>  drivers/zio/README            |  105 +++++++++++++++++++++++++++++++++
>  6 files changed, 471 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/zio/00-INDEX
>  create mode 100644 Documentation/zio/buffer.txt
>  create mode 100644 Documentation/zio/device.txt
>  create mode 100644 Documentation/zio/modules.txt
>  create mode 100644 Documentation/zio/trigger.txt
>  create mode 100644 drivers/zio/README
> 
> diff --git a/Documentation/zio/00-INDEX b/Documentation/zio/00-INDEX
> new file mode 100644
> index 0000000..093d9fb
> --- /dev/null
> +++ b/Documentation/zio/00-INDEX
> @@ -0,0 +1,10 @@
> +00-INDEX
> +	- this file
> +device.txt
> +	- description of what ZIO devices (and csets and channels) are.
> +buffer.txt
> +	- description of the buffer, it's methods and how it is used.
> +trigger.txt
> +	- what is a trigger and what's its role in ZIO.
> +modules.txt
> +	- list of modules (and description) found in the first ZIO package
> diff --git a/Documentation/zio/buffer.txt b/Documentation/zio/buffer.txt
> new file mode 100644
> index 0000000..f80e63a
> --- /dev/null
> +++ b/Documentation/zio/buffer.txt
> @@ -0,0 +1,114 @@
> +
> +ZIO defines a "buffer" object type, so each device can exploit any
> +features it may offer to speed up data transfers.
> +
> +Each cset in a device can use a different buffer, which is specified
> +as an attribute of the cset.  One instance of the buffer type exists
> +for each channel, and the char devices (control and data: see
> +device.txt) refer to the buffer.
> +
> +Please read <linux/zio-buffer.h> together with this file.
> +
> +	Buffer Types
> +	============
> +
> +Buffers may be device-specific or generic. A generic buffer called
> +"kmalloc" is provided within zio-core; it uses kmalloc for allocation
> +data blocks.  Such buffer is activated by default on all new csets
> +being registered but is not special in any other way, you can write
> +your own generic buffer (and if it's better than ours, we may use it
> +as default buffer in future releases).
> +
> +A device-specific buffer declares to be such within its attributes.  A
> +device-specific buffer can only be used by csets that declare its name
> +as preferred buffer type.  When such csets are registered, if the
> +buffer is already known to ZIO, it will be activated by default instead
> +of "kmalloc".
> +
> +Sometimes people write drivers for a set of similar devices, with
> +similar DMA capabilities. In this case, all of them may refer to the
> +same device-specific buffer type; the buffer type may be registered
> +as a standalone kernel module.
> +
> +The ZIO buffer data structures includes two sets of operations:
> +file_operations and buffer_operations.
> +
> +
> +	Buffer Operations
> +	=================
> +
> +Each buffer type must provide the following buffer operations. All
> +of them are implemented in zio-buf-kmalloc.c, which may be used as
> +reference to better understand the role of each method:
> +
> +	struct zio_bi *(*create)(struct zio_buffer_type *zbuf,
> +				 struct zio_channel *ch,
> +				 fmode_t f_flags);
> +	void (*destroy)(struct zio_bi *bi);
> +
> +The create() operation allocates and initializes an instance of the
> +buffer type. It is called by ZIO when a channel is opened for the
> +first time. The operation return a zio buffer instance (zio_bi),
> +which is the generic descriptor of a buffer instance. ZIO handles
> +only zio_bi, so complex buffer structures must contain the zio_bi
> +structure and use container_of() to access the private enclosing
> +structure.
> +
> +Destroy() deallocates a buffer instance. ZIO calls destroy when the
> +channel is unregistered from ZIO or when the user assigns a different
> +buffer type to the channel.
> +
> +When the control/data devices are closed, ZIO doesn't call destroy, so
> +incoming data can queue up while the application leaves it closed
> +(e.g., a shell script).  Actually, the release file operation is not
> +handled by ZIO, so it couldn't call destroy on close even if it wanted
> +to.
> +
> +	struct zio_block *(*alloc_block)(struct zio_bi *bi,
> +					 struct zio_control *ctrl,
> +					 size_t datalen, gfp_t gfp);
> +	void (*free_block)(struct zio_bi *bi, struct zio_block *block);
> +
> +For input channels, a block is allocated before the trigger fires, and
> +it is freed when the user has read or explicitly ignored it. For
> +output, allocation happens on user write and free is called by the
> +trigger when it is done. Thus, the functions are sometimes called by
> +buffer code itself, and sometimes by the trigger. The generic
> +structure hosting a block is zio_block which contain both data
> +(samples) and control informations.  If needed, buffers may use a more
> +complex structure, which will include zio_block, which is the only
> +structure that ZIO handles; by using container_of you can retrieve the
> +enclosing complex structure used in your buffer
> +
> +	int (*store_block)(struct zio_bi *bi, struct zio_block *block);
> +	struct zio_block (*retr_block) (struct zio_bi *bi);
> +
> +For input the trigger calls store_block() and the read system call issues
> +retr_block().  For output, the write system call runs store_block()
> +and the trigger may call retr_block() (although the buffer pushes to
> +the trigger when it receives the first data block).
> +
> +
> +	File Operations
> +	===============
> +
> +This field hosts the file_operations used by the char devices (control and
> +data) for every channel using this buffer type.  When char devices are
> +initially opened, the open method being run is within zio-code;
> +it  kmallocs f->private_data before calling the buffer-specific open
> +method. The private data being used is:
> +
> +	struct zio_f_priv {
> +		struct zio_channel *chan;
> +		enum zio_cdev_type type;
> +	};
> +
> +All buffer file operations can thus refer to the current channel (and
> +its buffer and its trigger), and know if the current file is
> +ZIO_CDEV_CTRL or ZIO_CDEV_DATA.  Every buffer is expected to
> +call zio_generic_release() at the end of its own release operation, or
> +used zio_generic_release() directly in the file operations.
> +
> +ZIO offers other generic file operations, that may be enough for your
> +buffer code or not. See zio-buf-kmalloc.c for a working example of
> +buffer file operations.
> diff --git a/Documentation/zio/device.txt b/Documentation/zio/device.txt
> new file mode 100644
> index 0000000..0c960e2
> --- /dev/null
> +++ b/Documentation/zio/device.txt
> @@ -0,0 +1,69 @@
> +
> +	ZIO Device
> +	==========
> +
> +A device, registered through zio_register_device() is the description
> +of an I/O peripheral. It is made up of channel-sets, called csets
> +from now on. A device may represent a PCI board or an SPI integrated
> +circuit or whatever it makes sense to manage from a single device driver.
> +All I/O operations are performed on csets, so the device is just an
> +array of csets.
> +
> +	Csets
> +	=====
> +
> +A cset (channel-set) is an homogeneous set of I/O channels. All
> +channels in the set are feature the same physical characteristics;
> +moreover, a cset refers to a trigger object, so all channels in a set
> +are triggered by the same event. This is the typical use case for
> +logic analysers (digital input) or multi-probe scopes (analog input),
> +as well as multi-waveform output. If your device has several input
> +channels which are separately triggered, they should be defined as
> +several cset items, each featuring one channel only.  Finally, all
> +channels in a cset use the same buffer object for in-kernel data
> +storage. Both the buffer and the trigger for a cset are set by
> +writing the proper name in sysfs. At device registration defaults
> +apply. If ZIO can't find the trigger/buffer name you wrote,
> +it will return EINVAL and leave the previous trigger/buffer in place.
> +
> +	Channels
> +	========
> +
> +The channel is the lowest object in the ZIO hierarchy. It represents
> +the single physical connector of the device: analog or digital, input
> +or output. Time-to-digital and digital-to-time devices can be represented
> +as channels as well.
> +
> +	Attributes
> +	==========
> +
> +Most configuration and information in ZIO happens through sysfs.
> +See sysfs.txt for information about attributes. (FIXME: sysfs.txt)
> +
> +	Data Transfers
> +	==============
> +
> +Data transfer in ZIO uses two char devices for each channel offered by
> +the driver. One char device is used to describe data blocks (we call
> +it control device); the other is used to transfer the data blocks (we
> +call it data device). The control device returns (or accepts) a
> +fixed-size structure that describes the next data transfer, including
> +the trigger in use, data size, number of samples and various
> +attributes.  Applications may choose to read the data device alone,
> +without retrieving control information: when any data of a new block
> +is transferred, the associated control information is discarded.
> +Similarly, data is discarded if you re-read the control device after
> +having retrieved the description of a data block you are not
> +interested in.  For output, writing data without writing control uses
> +the default control information, or the one from the previous
> +transfer.
> +
> +The full set of rules for data and control transfers is described
> +elsewhere (FIXME: link to other docs) but it is pretty intuitive once
> +you get the idea.
> +
> +See the "zio-dump" host tool in the top-level zio dir for an example
> +of generic and simple input application that shows use of control and
> +data files.
> +
> +
> diff --git a/Documentation/zio/modules.txt b/Documentation/zio/modules.txt
> new file mode 100644
> index 0000000..b3df00a
> --- /dev/null
> +++ b/Documentation/zio/modules.txt
> @@ -0,0 +1,45 @@
> +
> +This is the list of ZIO modules, at the time of writing. It is there
> +to help new users understanding how the parts stick together.
> +
> +  drivers/zio/zio-core.ko
> +
> +This module (which is linked from several source files) includes the
> +core sysfs and attribute management. It exports the register and
> +unregister functions for top-level objects. Moreover, it includes the
> +default buffer, called "kmalloc" and default trigger, called
> +"app-request".
> +
> +  drivers/zio/trigger/trig-ktimer.ko
> +  drivers/zio/trigger/trig-hrt.ko
> +  drivers/zio/trigger/trig-irq.ko
> +
> +Three other generic triggers. Two of them are time-based, and the
> +third hooks to an external interrupt (or more than one) as source of
> +trigger that can be used be any zio cset).
> +
> +  drivers/zio/dev/zio-null.ko
> +  drivers/zio/dev/zio-parport.ko
> +  drivers/zio/dev/zio-ad7888.ko
> +  drivers/zio/dev/zio-uart.ko
> +
> +These modules are examples. "null" does nothing: it discards output
> +data and returns zeroes as input data. It can be used to experiment
> +with generic triggers and as a sandbox for local modifications and
> +testing.
> +
> +The parport driver registers two output csets and two input cset.
> +In each group one cset is byte-oriented and the other is bit-oriented.
> +
> +The ad7888 is an SPI ADC we mounted on an ARM board. It's a real
> +8-channel ADC we are using for internal development, and this is a
> +real driver for a real thing. Over time it will handle its own buffer
> +type (our SPI master uses DMA) and its own data-driven trigger (even
> +if the data will be scanned by the CPU, so it can only work at low
> +data rates).
> +
> +The uart driver is a line discpline that can receive data from a
> +serial port. The first implementation expects to receive an endless
> +stream of 16-bit data, big endian (we used this to run on-board ADC on
> +cortex-m3), but we plan to extend it as a serious test case. You can
> +drive it from a pty slave, for example.
> diff --git a/Documentation/zio/trigger.txt b/Documentation/zio/trigger.txt
> new file mode 100644
> index 0000000..95b426f
> --- /dev/null
> +++ b/Documentation/zio/trigger.txt
> @@ -0,0 +1,128 @@
> +
> +ZIO defines a "trigger" object type, and each cset is connected to
> +a trigger.
> +
> +Each cset in a device can use a different trigger, which is specified
> +as an attribute of the cset.  When the trigger fires, it acts on all
> +the non-disabled channels of the cset.  Only the "app-request" trigger
> +can act on a single channel at a time.
> +
> +Please read <linux/zio-trigger.h> together with this file.
> +
> +	Trigger Types
> +	=============
> +
> +Triggers may be device-specific or generic. A few generic triggers
> +are part of zio-core. The "app-request" trigger fires input when
> +the application calls read and fires output when the application calls
> +write (it acts on a single channel). The "ktimer" trigger uses a kernel
> +timer as trigger source. The "irq" trigger uses any interrupt (e.g.,
> +a GPIO interrupt, or pin 10 of the PC parallel port) as trigger event.
> +
> +A device-specific trigger declares to be such within its attributes.  A
> +device-specific trigger can only be used by csets that declare its name
> +as preferred trigger type.  When such csets are registered, if the
> +trigger is already known to ZIO, it will be activated by default instead
> +of "app-request".
> +
> +	Trigger Operations
> +	==================
> +
> +Trigger operations are the following:
> +
> +	struct zio_ti *(*create)(struct zio_trigger_type *trig,
> +				 struct zio_cset *cset,
> +				 struct zio_control *ctrl,
> +				 fmode_t flags);
> +	void (*destroy)(struct zio_ti *ti);
> +
> +Create and destroy a trigger instance for a cset. ZIO calls create() when
> +attaching the trigger to a cset; it calls destroy() when the trigger is
> +replaced by a different one or the cset is being unregistered from ZIO.
> +The instance structure is trigger-specific, but it must include the
> +generic structure zio_ti. Every time this structure is passed over, trigger
> +code may use container_of if it needs to access the private enclosing
> +structure.
> +
> +	int (*config)(struct zio_ti *ti, stuct zio_control *ctrl);
> +
> +The method is called by ZIO whenever the attributes for a trigger
> +instance are modified by the user (by writing to sysfs or otherwise).
> +
> +	int (*push_block)(struct zio_ti *ti,
> +			  struct zio_channel *chan,
> +			  struct zio_control *ctrl);
> +
> +This is used for output channels: when a new data block is ready, it
> +must be sent to the trigger so it can be output when the event fires.
> +Buffer code, therefore, is expected to call this trigger method.  The
> +function can return -EAGAIN if it has no space in the queue, or 0 on
> +success. If EAGAIN happens, the buffer should handle it (by storing
> +locally or notifying the user).
> +
> +	void (*pull_block)(struct zio_ti *ti,
> +	  		   struct zio_channel *chan);
> +
> +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 of storing a block
> +when available.  Since driver->input_cset 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.
> +
> +        void (*data_done)(struct zio_cset *cset);
> +
> +The function is called by the device, and signals the trigger that
> +the input or output operation on the cset is over. For input, the
> +trigger will push blocks to the buffer, for output it will release
> +the blocks.  zio-core offers zio_generic_data_done() for triggers
> +that don't need special handling.
> +
> +	File Operations
> +	===============
> +
> +The trigger may include a non-NULL f_ops pointer. Most triggers will
> +not need it, but for example "app-request" does, because it needs to
> +look at individual read and write calls performed by applications.
> +ZIO will use these file operations (instead of the buffer file operations)
> +when the open method of the char device detects that the active trigger
> +declares a non-NULL f_ops field.  These operations will most
> +likely fall back to buffer->f_ops for most of their actual work.
> +
> +See zio-trig-app-request.c for details about how this is used.
> +
> +	When the trigger fires
> +	======================
> +
> +The trigger event may happen for a variety of reasons. It can be
> +time-driven, data-driven or whatever else.  In any case, there is
> +a time when the trigger fires, so input or output may happen.
> +(With most hardware-specific triggers, the actual input or output of
> +data has already happened when the trigger interrupt runs, but this
> +doesn't change the software flow).
> +
> +Hardware-driven triggers will need to make their own work by themselves,
> +but ZIO offers this help macro to loop over all non-disabled channels:
> +
> +	cset_for_each(struct zio_cset *cset, struct zio_channel *ch)
> +
> +The macro works like "task_for_each" or "list_for_each" in the kernel
> +headers.
> +
> +For software-based triggers (where actual I/O happens when software
> +wants it to happen, even if it is in response to an interrupt), the
> +asynchronous code that runs the event will just need to call
> +
> +	zio_fire_trigger(struct zio_ti *ti);
> +
> +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.
> +
> +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
> +implementation based on trigger-local file_operations.
> +
> diff --git a/drivers/zio/README b/drivers/zio/README
> new file mode 100644
> index 0000000..d537353
> --- /dev/null
> +++ b/drivers/zio/README
> @@ -0,0 +1,105 @@
> +
> +Zio is "the ultimate I/O framework".  Is being developed on the open
> +hardware repository at http://www.ohwr.org/projects/zio .
> +
> +This version is known to compile and run with kernels 2.6.34 onwards.
> +
> +This README refers to version "beta3", but work is ongoing towards
> +a stable package. See the TODO file on ohwr for details.
> +
> +To test zio you need to load the core modules (later, the default
> +trigger and default buffer will be part of zio-core):
> +
> +   	insmod zio-core.ko
> +   	insmod buffers/zio-buf-kmalloc.ko
> +   	insmod triggers/zio-trig-timer.ko
> +
> +Drivers can't live without a trigger and a buffer, so the modules above
> +must be loaded first.
> +
> +The kmalloc buffer is a simple buffer that hosts a list of data blocks,
> +for either input or output.
> +
> +The timer trigger is a kernel-timer based trigger, that fires a block
> +transfer on a timely basis. You can use the "ms" parameter to set the
> +inter-block time, in milliseconds (the default is two seconds). You
> +can also pass the "nsamples" parameter to say how many samples are
> +aquired at each trigger instance.
> +
> +With the core in place, you can load a driver:
> +
> +	insmod drivers/zio-zero.ko
> +
> +zio-zero has a single channel-set (number 0) with three channels.
> +They simulate three analog inputs, 8-bit per sample.
> +
> +     channel 0: returns zero forever
> +     channel 1: returns random numbers
> +     channel 2: returns a sawtooth signal (0 to 255 and back)
> +
> +The char devices are called using device-cset-channel:
> +
> +    /dev/zzero-0-0-ctrl
> +    /dev/zzero-0-0-data
> +    /dev/zzero-0-1-ctrl
> +    /dev/zzero-0-1-data
> +    /dev/zzero-0-2-ctrl
> +    /dev/zzero-0-2-data
> +
> +(later versions will use a /dev/zio/ directory for all zio files)
> +
> +To read data you can just cat, or "od -t x1" the data device.
> +To get control information meta-information) together with data, you
> +can use the "zio-dump" user-space utility, in this directory.
> +
> +For example:
> +
> +    ./zio-dump /dev/zzero-0-2-ctrl /dev/zzero-0-2-data
> +
> +This is the result with a trigger that uses 2000 as msec and 32
> +as nsample:
> +
> +    ./zio-dump /dev/zzero-0-2-ctrl /dev/zzero-0-2-data
> +
> +    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 2
> +    Ctrl: seq 1, n 32, size 1, bits 8, flags 01000001 (little-endian)
> +    Ctrl: stamp 1320403540.084798370 (0)
> +    Data: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
> +    Data: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
> +
> +    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 2
> +    Ctrl: seq 2, n 32, size 1, bits 8, flags 01000001 (little-endian)
> +    Ctrl: stamp 1320403542.091093781 (0)
> +    Data: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
> +    Data: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
> +
> +    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 2
> +    Ctrl: seq 3, n 32, size 1, bits 8, flags 01000001 (little-endian)
> +    Ctrl: stamp 1320403544.084790274 (0)
> +    Data: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
> +    Data: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
> +
> +Zio dump is able to access several pairs of devices (control and data),
> +and you can change the trigger and buffer attributes for the cset.
> +
> +Example:
> +
> +    echo 500 > /sys/zio/devices/zzero/cset0/trigger/ms-period
> +    echo 4 > /sys/zio/devices/zzero/cset0/trigger/nsamples
> +    echo 3 > /sys/zio/devices/zzero/cset0/chan0/buffer/max-buffer-len
> +    ./zio-dump /dev/zzero-0-*
> +
> +    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 0
> +    Ctrl: seq 102, n 4, size 1, bits 8, flags 01000001 (little-endian)
> +    Ctrl: stamp 4066.519285605 (0)
> +    Data: 00 00 00 00
> +
> +    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 1
> +    Ctrl: seq 102, n 4, size 1, bits 8, flags 01000001 (little-endian)
> +    Ctrl: stamp 4066.519285605 (0)
> +    Data: 71 29 a6 53
> +
> +    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 2
> +    Ctrl: seq 102, n 4, size 1, bits 8, flags 01000001 (little-endian)
> +    Ctrl: stamp 4066.519285605 (0)
> +    Data: 60 61 62 63
Interesting approach to meta data handling.  It's kind of 'partly' out
of band as it can apply to large chunks of data.

How does it map if you have triggers causing single captures from each
channel?  I would imagine you will then store a whole meta data set per
sample?  I know this isn't your use case, but I'm currious to see where
the overlap lies between this and IIO as you can imagine!

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 1/7] Documentation: add docs for drivers/zio
  2011-11-26 17:30 ` [RFC PATCH 1/7] Documentation: add docs for drivers/zio Alessandro Rubini
  2011-11-26 20:00   ` Greg KH
  2011-11-26 22:16   ` Jonathan Cameron
@ 2011-11-26 22:53   ` Alessandro Rubini
  2011-12-06  5:12   ` Randy Dunlap
  3 siblings, 0 replies; 25+ messages in thread
From: Alessandro Rubini @ 2011-11-26 22:53 UTC (permalink / raw)
  To: jic23
  Cc: linux-iio, greg, linux-kernel, federico.vaga, dcobas, siglesia,
	manohar.vanga

zio readme:
>> +    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 2
>> +    Ctrl: seq 102, n 4, size 1, bits 8, flags 01000001 (little-endian)
>> +    Ctrl: stamp 4066.519285605 (0)
>> +    Data: 60 61 62 63

Jonathan  Cameron:
> Interesting approach to meta data handling.  It's kind of 'partly' out
> of band as it can apply to large chunks of data.

Exactly. Then, you can ignore the metadata if you want. It's like
having a line of packed food, with detailed labels. You can read the
label before getting each content blob, or just read the blob and
discard the label.  Or you can pass everything to someone else, for
off-line handling.

We are aware there is a serious overhead if blocks are small, but the
use case is different, as said.

> How does it map if you have triggers causing single captures from each
> channel?  I would imagine you will then store a whole meta data set per
> sample?

Yes. Worse: csets are acquired (or output) concurrently, so there's
one control structure per channel (actually, gain and offset may be
different in each channel, so there's a reason).

But when blocks are acquired by a hardware card with 256MB of internal
memory and then transferred in a single DMA burst for offline
analysis, then the overhead is negligible and I see an advantage in
simplicity.

Actually, we are considering a buffer that reassembles samples,
returning bigger blocks on demand, so we get rid of some of the
overhead.  But that's more a stress-test for the buffer concept than
for real use cases.

Sure we lack any in-kernel users and don't want to have them in the
future, that's helping us a lot.

> I know this isn't your use case, but I'm currious to see where
> the overlap lies between this and IIO as you can imagine!

Yes, we are too. Federico has an ad7888 driver working, both for IIO
and ZIO (and Comedi, but that's out of the game already), and we are
going to write for a few more IIO-supported devices. In this way we
both validate (or not) our design and compare with IIO.

Thank you for your feedback, both here and in the off-list email.

/alessandro

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 3/7] drivers/zio: core files for the ZIO input/output
  2011-11-26 20:03   ` Greg KH
@ 2011-11-26 22:58     ` Federico Vaga
  2011-11-27  9:33       ` Greg KH
  0 siblings, 1 reply; 25+ messages in thread
From: Federico Vaga @ 2011-11-26 22:58 UTC (permalink / raw)
  To: Greg KH
  Cc: Alessandro Rubini, linux-iio, linux-kernel, dcobas, siglesia,
	manohar.vanga

In data sabato 26 novembre 2011 12:03:41, Greg KH ha scritto:
> On Sat, Nov 26, 2011 at 06:30:42PM +0100, Alessandro Rubini wrote:
> > +static struct kobj_type zdktype = { /* For standard and extended
> > attribute */ +	.release   = NULL,
> 
> Sweet!
> 
> As-per the in-kernel documentation, I now get to mock you for doing
> this :)
> 
> Please NEVER DO THIS, you are ignoring the messages that the kernel
> sends you when you remove one of these devices, and causing a memory
> leak.

Honestly we never see any messages about this.

> Not nice at all, yet another reason to use a 'struct device'.

I don't think is a valid reason, because device_release implementation require 
us to implement a release method within device, or device_type or class; so we 
can use kobj_type as well.

> thanks,
> 
> greg k-h
-- 
Federico Vaga

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 2/7] include/linux: add headers for drivers/zio
  2011-11-26 21:46     ` Federico Vaga
@ 2011-11-27  9:32       ` Greg KH
  2011-11-28 14:56         ` Federico Vaga
  0 siblings, 1 reply; 25+ messages in thread
From: Greg KH @ 2011-11-27  9:32 UTC (permalink / raw)
  To: Federico Vaga
  Cc: Alessandro Rubini, linux-iio, linux-kernel, dcobas, siglesia,
	manohar.vanga

On Sat, Nov 26, 2011 at 10:46:48PM +0100, Federico Vaga wrote:
> In data sabato 26 novembre 2011 12:02:16, Greg KH ha scritto:
> > On Sat, Nov 26, 2011 at 06:30:31PM +0100, Alessandro Rubini wrote:
> > > +/*
> > > + * We use the same functions to deal with attributes, but the structures
> > > + * we act on may be different (dev, cset, channel). Thus, all structures
> > > + * begin with the type identifier, and zio_obj_head is used in
> > > container_of + */
> > 
> > Because you are using container_of, you don't have to have the structure
> > at the beginning of the structure it is included in, right?
> 
> Different structures have similar features and we use zio_obj_head->zobj_type to 
> identify the correct container_of to apply.  Sometimes we use the head only, so 
> we delay container_of later. 

That's usually not a good idea, which is why we don't do it generally in
the rest of the kernel.

You should "almost" always already know the type of device you are
pointing to when pointing to it, so that you can properly dereference
it.  I think you are doing the right thing here, but the true test would
be to move that structure somewhere else other than "first" and see what
breaks.

> > > +enum zio_object_type {
> > > +   ZNONE = 0,      /* reserved for non zio object */
> > > +   ZDEV, ZCSET, ZCHAN,
> > > +   ZTRIG, ZTI,     /* trigger and trigger instance */
> > > +   ZBUF, ZBI,      /* buffer and buffer instance */
> > > +};
> > > +
> > > +/* zio_obj_head is for internal use only, as explained above */
> > > +struct zio_obj_head {
> > > +   struct kobject          kobj;
> > > +   enum zio_object_type    zobj_type;
> > > +   char                    name[ZIO_NAME_LEN];
> > > +};
> > > +#define to_zio_head(_kobj) container_of(_kobj, struct zio_obj_head, kobj)
> > > +#define to_zio_dev(_kobj) container_of(_kobj, struct zio_device,
> > > head.kobj) +#define to_zio_cset(_kobj) container_of(_kobj, struct
> > > zio_cset, head.kobj) +#define to_zio_chan(_kobj) container_of(_kobj,
> > > struct zio_channel, head.kobj)
> > Why are you using a "raw" kobject and not 'struct device' instead? 
> 
> The device way was experimented and we can move in that direction. I also 
> tried a mixed solution with device and kobject, because not all the zio objects 
> can be device.
> 
> I decided to use the kobject way because it was an easier and flexible solution 
> for a fast development.
> 
> > If you use a kobject, you loose all of the device tree information that a
> > real struct device provides to userspace,
> 
> You mean the device sysfs tree? Acctually we don't need that information

Yes you do, you are already using it, right?

By using kobjects you "skip" notifying userspace the whole tree and it
only knows about "parts" of it, which is why you should not do this.

> > and can only cause confusion in the long run.
> 
> I think it can be confusing to declare a device what is not a device, for 
> example: buffer, trigger, channel-set (maybe in some 
> sense can be a device) and channel 

Nope, they seem like "devices" to me in that you want them showing up in
sysfs, which is why you used kobjects, right?  Because of that, you are
in the device tree, so you need to use a 'struct device'.

> > This also will provide you the "type" and name that you are needing
> > here, as well as lots of other good things (properly formatted logging
> > messages, uevents, etc.)
> 
> If you refer to device_type, I think it is too complex for our purpose (also 
> tried during the device "experiment"), we only need to recognize a zio object, 
> we don't need al the stuff within device_type.
> 
> You are right, device is full of great things and the migration to device is 
> always a point of discussion, but actually kobject meet well with our needs.

I beg to differ.

> > Please consider moving to that instead.
> 
> We can re-evaluate and better explain the choice if kobj is still the 
> preferrable one

kobject is not the preferrable one, sorry.

greg k-h

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 3/7] drivers/zio: core files for the ZIO input/output
  2011-11-26 22:58     ` Federico Vaga
@ 2011-11-27  9:33       ` Greg KH
  2011-11-28 14:59         ` Federico Vaga
  0 siblings, 1 reply; 25+ messages in thread
From: Greg KH @ 2011-11-27  9:33 UTC (permalink / raw)
  To: Federico Vaga
  Cc: Alessandro Rubini, linux-iio, linux-kernel, dcobas, siglesia,
	manohar.vanga

On Sat, Nov 26, 2011 at 11:58:41PM +0100, Federico Vaga wrote:
> In data sabato 26 novembre 2011 12:03:41, Greg KH ha scritto:
> > On Sat, Nov 26, 2011 at 06:30:42PM +0100, Alessandro Rubini wrote:
> > > +static struct kobj_type zdktype = { /* For standard and extended
> > > attribute */ +	.release   = NULL,
> > 
> > Sweet!
> > 
> > As-per the in-kernel documentation, I now get to mock you for doing
> > this :)
> > 
> > Please NEVER DO THIS, you are ignoring the messages that the kernel
> > sends you when you remove one of these devices, and causing a memory
> > leak.
> 
> Honestly we never see any messages about this.

Really?  Then you never removed that kobject from memory.  Please go
read the kobject documentation for more details.

> > Not nice at all, yet another reason to use a 'struct device'.
> 
> I don't think is a valid reason, because device_release implementation require 
> us to implement a release method within device, or device_type or class; so we 
> can use kobj_type as well.

True, but it tries to make things easier to not get wrong, like you are
here.

Please fix this.

greg k-h

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 2/7] include/linux: add headers for drivers/zio
  2011-11-27  9:32       ` Greg KH
@ 2011-11-28 14:56         ` Federico Vaga
  2011-11-30  6:21           ` Greg KH
  0 siblings, 1 reply; 25+ messages in thread
From: Federico Vaga @ 2011-11-28 14:56 UTC (permalink / raw)
  To: Greg KH
  Cc: Alessandro Rubini, linux-iio, linux-kernel, dcobas, siglesia,
	manohar.vanga

2011/11/27 Greg KH <greg@kroah.com>:
> On Sat, Nov 26, 2011 at 10:46:48PM +0100, Federico Vaga wrote:
>> In data sabato 26 novembre 2011 12:02:16, Greg KH ha scritto:
>> > On Sat, Nov 26, 2011 at 06:30:31PM +0100, Alessandro Rubini wrote:
>> > > +/*
>> > > + * We use the same functions to deal with attributes, but the structures
>> > > + * we act on may be different (dev, cset, channel). Thus, all structures
>> > > + * begin with the type identifier, and zio_obj_head is used in
>> > > container_of + */
>> >
>> > Because you are using container_of, you don't have to have the structure
>> > at the beginning of the structure it is included in, right?
>>
>> Different structures have similar features and we use zio_obj_head->zobj_type to
>> identify the correct container_of to apply.  Sometimes we use the head only, so
>> we delay container_of later.
>
> That's usually not a good idea, which is why we don't do it generally in
> the rest of the kernel.
>
> You should "almost" always already know the type of device you are
> pointing to when pointing to it, so that you can properly dereference
> it.  I think you are doing the right thing here, but the true test would
> be to move that structure somewhere else other than "first" and see what
> breaks.

One of our next commits will be the moving of this field somewhere
else in the structures for bug finding. Thank you for the suggestion.

>> > > +enum zio_object_type {
>> > > +   ZNONE = 0,      /* reserved for non zio object */
>> > > +   ZDEV, ZCSET, ZCHAN,
>> > > +   ZTRIG, ZTI,     /* trigger and trigger instance */
>> > > +   ZBUF, ZBI,      /* buffer and buffer instance */
>> > > +};
>> > > +
>> > > +/* zio_obj_head is for internal use only, as explained above */
>> > > +struct zio_obj_head {
>> > > +   struct kobject          kobj;
>> > > +   enum zio_object_type    zobj_type;
>> > > +   char                    name[ZIO_NAME_LEN];
>> > > +};
>> > > +#define to_zio_head(_kobj) container_of(_kobj, struct zio_obj_head, kobj)
>> > > +#define to_zio_dev(_kobj) container_of(_kobj, struct zio_device,
>> > > head.kobj) +#define to_zio_cset(_kobj) container_of(_kobj, struct
>> > > zio_cset, head.kobj) +#define to_zio_chan(_kobj) container_of(_kobj,
>> > > struct zio_channel, head.kobj)
>> > Why are you using a "raw" kobject and not 'struct device' instead?
>>
>> The device way was experimented and we can move in that direction. I also
>> tried a mixed solution with device and kobject, because not all the zio objects
>> can be device.
>>
>> I decided to use the kobject way because it was an easier and flexible solution
>> for a fast development.
>>
>> > If you use a kobject, you loose all of the device tree information that a
>> > real struct device provides to userspace,
>>
>> You mean the device sysfs tree? Acctually we don't need that information
>
> Yes you do, you are already using it, right?
>
> By using kobjects you "skip" notifying userspace the whole tree and it
> only knows about "parts" of it, which is why you should not do this.
>
>> > and can only cause confusion in the long run.
>>
>> I think it can be confusing to declare a device what is not a device, for
>> example: buffer, trigger, channel-set (maybe in some
>> sense can be a device) and channel
>
> Nope, they seem like "devices" to me in that you want them showing up in
> sysfs, which is why you used kobjects, right?  Because of that, you are
> in the device tree, so you need to use a 'struct device'.
>
>> > This also will provide you the "type" and name that you are needing
>> > here, as well as lots of other good things (properly formatted logging
>> > messages, uevents, etc.)
>>
>> If you refer to device_type, I think it is too complex for our purpose (also
>> tried during the device "experiment"), we only need to recognize a zio object,
>> we don't need al the stuff within device_type.
>>
>> You are right, device is full of great things and the migration to device is
>> always a point of discussion, but actually kobject meet well with our needs.
>
> I beg to differ.
>
>> > Please consider moving to that instead.
>>
>> We can re-evaluate and better explain the choice if kobj is still the
>> preferrable one
>
> kobject is not the preferrable one, sorry.

I don't reply to each point because I suppose the point is: "kobject
or device for sysfs?", maybe I misunderstood.
I know that it is not a good thing reply with a new question, but I
think it can clarify the problem.

Why device is it preferred to export some sysfs attributes when sysfs
ask me kobject?

As I tested both device and kobject, I'll do a parallel implementation
with device.

> greg k-h
>



-- 
Federico Vaga

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 3/7] drivers/zio: core files for the ZIO input/output
  2011-11-27  9:33       ` Greg KH
@ 2011-11-28 14:59         ` Federico Vaga
  0 siblings, 0 replies; 25+ messages in thread
From: Federico Vaga @ 2011-11-28 14:59 UTC (permalink / raw)
  To: Greg KH
  Cc: Alessandro Rubini, linux-iio, linux-kernel, dcobas, siglesia,
	manohar.vanga

2011/11/27 Greg KH <greg@kroah.com>:
> On Sat, Nov 26, 2011 at 11:58:41PM +0100, Federico Vaga wrote:
>> In data sabato 26 novembre 2011 12:03:41, Greg KH ha scritto:
>> > On Sat, Nov 26, 2011 at 06:30:42PM +0100, Alessandro Rubini wrote:
>> > > +static struct kobj_type zdktype = { /* For standard and extended
>> > > attribute */ +    .release   = NULL,
>> >
>> > Sweet!
>> >
>> > As-per the in-kernel documentation, I now get to mock you for doing
>> > this :)
>> >
>> > Please NEVER DO THIS, you are ignoring the messages that the kernel
>> > sends you when you remove one of these devices, and causing a memory
>> > leak.
>>
>> Honestly we never see any messages about this.
>
> Really?  Then you never removed that kobject from memory.  Please go
> read the kobject documentation for more details.

Yes. All the kobjects are correctly removed and no memory leak was found.

I took a look into kobject.c and I found (I suppose) the message but
it is a pr_debug(); if it is so important we can think to "promote" it
to pr_warning()

>> > Not nice at all, yet another reason to use a 'struct device'.
>>
>> I don't think is a valid reason, because device_release implementation require
>> us to implement a release method within device, or device_type or class; so we
>> can use kobj_type as well.
>
> True, but it tries to make things easier to not get wrong, like you are
> here.
>
> Please fix this.

I'll fix it

> greg k-h
>



-- 
Federico Vaga

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 2/7] include/linux: add headers for drivers/zio
  2011-11-28 14:56         ` Federico Vaga
@ 2011-11-30  6:21           ` Greg KH
  0 siblings, 0 replies; 25+ messages in thread
From: Greg KH @ 2011-11-30  6:21 UTC (permalink / raw)
  To: Federico Vaga
  Cc: Alessandro Rubini, linux-iio, linux-kernel, dcobas, siglesia,
	manohar.vanga

On Mon, Nov 28, 2011 at 03:56:45PM +0100, Federico Vaga wrote:
> I don't reply to each point because I suppose the point is: "kobject
> or device for sysfs?", maybe I misunderstood.

That is correct.

> I know that it is not a good thing reply with a new question, but I
> think it can clarify the problem.
> 
> Why device is it preferred to export some sysfs attributes when sysfs
> ask me kobject?

If your code is working properly, you don't have to ever make sysfs
calls, only driver core calls, for sysfs files.  There might be a few
minor exceptions, but I think the coverage is all there now.

> As I tested both device and kobject, I'll do a parallel implementation
> with device.

As you are using a tree of devices, please use struct device, I can't
accept the code otherwise.

greg k-h

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 0/7] Introducing ZIO, a new I/O framework
  2011-11-26 19:11 ` Alessandro Rubini
@ 2011-12-01 21:41   ` Linus Walleij
  0 siblings, 0 replies; 25+ messages in thread
From: Linus Walleij @ 2011-12-01 21:41 UTC (permalink / raw)
  To: Alessandro Rubini
  Cc: lars, linux-iio, greg, linux-kernel, federico.vaga, dcobas,
	siglesia, manohar.vanga

2011/11/26 Alessandro Rubini <rubini@gnudd.com>:

> I'm open to suggestions (_we_ are) about how to easily use IIO for
> output, for hardware timestamps (we have 3 32-bit fields) and for very
> large data blocks, with DMA to/from user space -- sure we don't have this
> last point in ZIO at this point in time.

The latter seem like a case for the dma-buf mechanism.
http://lwn.net/Articles/462524/

(Interesting hardware you found Alessandro! :)

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 1/7] Documentation: add docs for drivers/zio
  2011-11-26 17:30 ` [RFC PATCH 1/7] Documentation: add docs for drivers/zio Alessandro Rubini
                     ` (2 preceding siblings ...)
  2011-11-26 22:53   ` Alessandro Rubini
@ 2011-12-06  5:12   ` Randy Dunlap
  3 siblings, 0 replies; 25+ messages in thread
From: Randy Dunlap @ 2011-12-06  5:12 UTC (permalink / raw)
  To: Alessandro Rubini
  Cc: linux-iio, greg, linux-kernel, federico.vaga, dcobas, siglesia,
	manohar.vanga

On 11/26/2011 09:30 AM, Alessandro Rubini wrote:
> This is documentation for the beta3 release of zio.
> The files match commit 7d37663 in git://ohwr.org/misc/zio.git .
> 
> We are aware the "modules.txt" file is not correct as it lists files
> that are not ready. We decided to avoid fixing it for this RFC
> submission, which won't go upstream anyways.
> 
> Signed-off-by: Alessandro Rubini <rubini@gnudd.com>
> Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
> Acked-by: Juan David Gonzalez Cobas <dcobas@cern.ch>
> Acked-by: Samuel Iglesias Gonsalvez <siglesia@cern.ch>
> Acked-by: Manohar Vanga <manohar.vanga@cern.ch>
> ---
>  Documentation/zio/00-INDEX    |   10 +++
>  Documentation/zio/buffer.txt  |  114 ++++++++++++++++++++++++++++++++++++
>  Documentation/zio/device.txt  |   69 ++++++++++++++++++++++
>  Documentation/zio/modules.txt |   45 ++++++++++++++
>  Documentation/zio/trigger.txt |  128 +++++++++++++++++++++++++++++++++++++++++
>  drivers/zio/README            |  105 +++++++++++++++++++++++++++++++++
>  6 files changed, 471 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/zio/00-INDEX
>  create mode 100644 Documentation/zio/buffer.txt
>  create mode 100644 Documentation/zio/device.txt
>  create mode 100644 Documentation/zio/modules.txt
>  create mode 100644 Documentation/zio/trigger.txt
>  create mode 100644 drivers/zio/README
> 
> diff --git a/Documentation/zio/00-INDEX b/Documentation/zio/00-INDEX
> new file mode 100644
> index 0000000..093d9fb
> --- /dev/null
> +++ b/Documentation/zio/00-INDEX
> @@ -0,0 +1,10 @@
> +00-INDEX
> +	- this file
> +device.txt
> +	- description of what ZIO devices (and csets and channels) are.
> +buffer.txt
> +	- description of the buffer, it's methods and how it is used.

	                             its

> +trigger.txt
> +	- what is a trigger and what's its role in ZIO.
> +modules.txt
> +	- list of modules (and description) found in the first ZIO package

> diff --git a/Documentation/zio/buffer.txt b/Documentation/zio/buffer.txt
> new file mode 100644
> index 0000000..f80e63a
> --- /dev/null
> +++ b/Documentation/zio/buffer.txt
> @@ -0,0 +1,114 @@
> +
> +ZIO defines a "buffer" object type, so each device can exploit any
> +features it may offer to speed up data transfers.
> +
> +Each cset in a device can use a different buffer, which is specified
> +as an attribute of the cset.  One instance of the buffer type exists
> +for each channel, and the char devices (control and data: see
> +device.txt) refer to the buffer.
> +
> +Please read <linux/zio-buffer.h> together with this file.
> +
> +	Buffer Types
> +	============
> +
> +Buffers may be device-specific or generic. A generic buffer called
> +"kmalloc" is provided within zio-core; it uses kmalloc for allocation
> +data blocks.  Such buffer is activated by default on all new csets
> +being registered but is not special in any other way, you can write

                                                    way.  You can write

> +your own generic buffer (and if it's better than ours, we may use it
> +as default buffer in future releases).
> +
> +A device-specific buffer declares to be such within its attributes.  A
> +device-specific buffer can only be used by csets that declare its name
> +as preferred buffer type.  When such csets are registered, if the
> +buffer is already known to ZIO, it will be activated by default instead
> +of "kmalloc".
> +
> +Sometimes people write drivers for a set of similar devices, with
> +similar DMA capabilities. In this case, all of them may refer to the
> +same device-specific buffer type; the buffer type may be registered
> +as a standalone kernel module.
> +
> +The ZIO buffer data structures includes two sets of operations:
> +file_operations and buffer_operations.
> +
> +
> +	Buffer Operations
> +	=================
> +
> +Each buffer type must provide the following buffer operations. All
> +of them are implemented in zio-buf-kmalloc.c, which may be used as
> +reference to better understand the role of each method:
> +
> +	struct zio_bi *(*create)(struct zio_buffer_type *zbuf,
> +				 struct zio_channel *ch,
> +				 fmode_t f_flags);
> +	void (*destroy)(struct zio_bi *bi);
> +
> +The create() operation allocates and initializes an instance of the
> +buffer type. It is called by ZIO when a channel is opened for the
> +first time. The operation return a zio buffer instance (zio_bi),

                             returns a

> +which is the generic descriptor of a buffer instance. ZIO handles
> +only zio_bi, so complex buffer structures must contain the zio_bi
> +structure and use container_of() to access the private enclosing
> +structure.
> +
> +Destroy() deallocates a buffer instance. ZIO calls destroy when the

   destroy()                                          destroy()


> +channel is unregistered from ZIO or when the user assigns a different
> +buffer type to the channel.
> +
> +When the control/data devices are closed, ZIO doesn't call destroy, so

                                                              destroy(), so

> +incoming data can queue up while the application leaves it closed
> +(e.g., a shell script).  Actually, the release file operation is not
> +handled by ZIO, so it couldn't call destroy on close even if it wanted
> +to.
> +
> +	struct zio_block *(*alloc_block)(struct zio_bi *bi,
> +					 struct zio_control *ctrl,
> +					 size_t datalen, gfp_t gfp);
> +	void (*free_block)(struct zio_bi *bi, struct zio_block *block);
> +
> +For input channels, a block is allocated before the trigger fires, and
> +it is freed when the user has read or explicitly ignored it. For
> +output, allocation happens on user write and free is called by the
> +trigger when it is done. Thus, the functions are sometimes called by
> +buffer code itself, and sometimes by the trigger. The generic
> +structure hosting a block is zio_block which contain both data
> +(samples) and control informations.  If needed, buffers may use a more

                         information.

> +complex structure, which will include zio_block, which is the only
> +structure that ZIO handles; by using container_of you can retrieve the
> +enclosing complex structure used in your buffer

                                            buffer.

> +
> +	int (*store_block)(struct zio_bi *bi, struct zio_block *block);
> +	struct zio_block (*retr_block) (struct zio_bi *bi);
> +
> +For input the trigger calls store_block() and the read system call issues
> +retr_block().  For output, the write system call runs store_block()
> +and the trigger may call retr_block() (although the buffer pushes to
> +the trigger when it receives the first data block).
> +
> +
> +	File Operations
> +	===============
> +
> +This field hosts the file_operations used by the char devices (control and

   This structure holds

> +data) for every channel using this buffer type.  When char devices are
> +initially opened, the open method being run is within zio-code;
> +it  kmallocs f->private_data before calling the buffer-specific open
> +method. The private data being used is:
> +
> +	struct zio_f_priv {
> +		struct zio_channel *chan;
> +		enum zio_cdev_type type;
> +	};
> +
> +All buffer file operations can thus refer to the current channel (and
> +its buffer and its trigger), and know if the current file is
> +ZIO_CDEV_CTRL or ZIO_CDEV_DATA.  Every buffer is expected to
> +call zio_generic_release() at the end of its own release operation, or
> +used zio_generic_release() directly in the file operations.
> +
> +ZIO offers other generic file operations, that may be enough for your

drop comma above.

> +buffer code or not. See zio-buf-kmalloc.c for a working example of

               or may not.

> +buffer file operations.

> diff --git a/Documentation/zio/device.txt b/Documentation/zio/device.txt
> new file mode 100644
> index 0000000..0c960e2
> --- /dev/null
> +++ b/Documentation/zio/device.txt
> @@ -0,0 +1,69 @@
> +
> +	ZIO Device
> +	==========
> +
> +A device, registered through zio_register_device() is the description

drop comma above.

> +of an I/O peripheral. It is made up of channel-sets, called csets
> +from now on. A device may represent a PCI board or an SPI integrated
> +circuit or whatever it makes sense to manage from a single device driver.
> +All I/O operations are performed on csets, so the device is just an
> +array of csets.
> +
> +	Csets
> +	=====
> +
> +A cset (channel-set) is an homogeneous set of I/O channels. All
> +channels in the set are feature the same physical characteristics;

drop                   are ??

> +moreover, a cset refers to a trigger object, so all channels in a set
> +are triggered by the same event. This is the typical use case for
> +logic analysers (digital input) or multi-probe scopes (analog input),
> +as well as multi-waveform output. If your device has several input
> +channels which are separately triggered, they should be defined as
> +several cset items, each featuring one channel only.  Finally, all
> +channels in a cset use the same buffer object for in-kernel data
> +storage. Both the buffer and the trigger for a cset are set by
> +writing the proper name in sysfs. At device registration defaults
> +apply. If ZIO can't find the trigger/buffer name you wrote,
> +it will return EINVAL and leave the previous trigger/buffer in place.
> +
> +	Channels
> +	========
> +
> +The channel is the lowest object in the ZIO hierarchy. It represents
> +the single physical connector of the device: analog or digital, input
> +or output. Time-to-digital and digital-to-time devices can be represented
> +as channels as well.
> +
> +	Attributes
> +	==========
> +
> +Most configuration and information in ZIO happens through sysfs.
> +See sysfs.txt for information about attributes. (FIXME: sysfs.txt)
> +
> +	Data Transfers
> +	==============
> +
> +Data transfer in ZIO uses two char devices for each channel offered by
> +the driver. One char device is used to describe data blocks (we call
> +it control device); the other is used to transfer the data blocks (we
> +call it data device). The control device returns (or accepts) a
> +fixed-size structure that describes the next data transfer, including
> +the trigger in use, data size, number of samples and various
> +attributes.  Applications may choose to read the data device alone,
> +without retrieving control information: when any data of a new block
> +is transferred, the associated control information is discarded.
> +Similarly, data is discarded if you re-read the control device after
> +having retrieved the description of a data block you are not
> +interested in.  For output, writing data without writing control uses
> +the default control information, or the one from the previous
> +transfer.
> +
> +The full set of rules for data and control transfers is described
> +elsewhere (FIXME: link to other docs) but it is pretty intuitive once
> +you get the idea.
> +
> +See the "zio-dump" host tool in the top-level zio dir for an example

                                                     directory

> +of generic and simple input application that shows use of control and

   of a generic and simple

> +data files.
> +
> +

Drop ending blank lines.

> diff --git a/Documentation/zio/modules.txt b/Documentation/zio/modules.txt
> new file mode 100644
> index 0000000..b3df00a
> --- /dev/null
> +++ b/Documentation/zio/modules.txt
> @@ -0,0 +1,45 @@
> +
> +This is the list of ZIO modules, at the time of writing. It is there

                                                                  here

> +to help new users understanding how the parts stick together.
> +
> +  drivers/zio/zio-core.ko
> +
> +This module (which is linked from several source files) includes the
> +core sysfs and attribute management. It exports the register and
> +unregister functions for top-level objects. Moreover, it includes the
> +default buffer, called "kmalloc" and default trigger, called
> +"app-request".
> +
> +  drivers/zio/trigger/trig-ktimer.ko
> +  drivers/zio/trigger/trig-hrt.ko
> +  drivers/zio/trigger/trig-irq.ko
> +
> +Three other generic triggers. Two of them are time-based, and the
> +third hooks to an external interrupt (or more than one) as source of
> +trigger that can be used be any zio cset).
> +
> +  drivers/zio/dev/zio-null.ko
> +  drivers/zio/dev/zio-parport.ko
> +  drivers/zio/dev/zio-ad7888.ko
> +  drivers/zio/dev/zio-uart.ko
> +
> +These modules are examples. "null" does nothing: it discards output
> +data and returns zeroes as input data. It can be used to experiment
> +with generic triggers and as a sandbox for local modifications and
> +testing.
> +
> +The parport driver registers two output csets and two input cset.

                                                               csets.

> +In each group one cset is byte-oriented and the other is bit-oriented.
> +
> +The ad7888 is an SPI ADC we mounted on an ARM board. It's a real
> +8-channel ADC we are using for internal development, and this is a
> +real driver for a real thing. Over time it will handle its own buffer
> +type (our SPI master uses DMA) and its own data-driven trigger (even
> +if the data will be scanned by the CPU, so it can only work at low
> +data rates).
> +
> +The uart driver is a line discpline that can receive data from a

       UART                  discipline

> +serial port. The first implementation expects to receive an endless
> +stream of 16-bit data, big endian (we used this to run on-board ADC on
> +cortex-m3), but we plan to extend it as a serious test case. You can
> +drive it from a pty slave, for example.

> diff --git a/Documentation/zio/trigger.txt b/Documentation/zio/trigger.txt
> new file mode 100644
> index 0000000..95b426f
> --- /dev/null
> +++ b/Documentation/zio/trigger.txt
> @@ -0,0 +1,128 @@
> +
> +ZIO defines a "trigger" object type, and each cset is connected to
> +a trigger.
> +
> +Each cset in a device can use a different trigger, which is specified
> +as an attribute of the cset.  When the trigger fires, it acts on all
> +the non-disabled channels of the cset.  Only the "app-request" trigger
> +can act on a single channel at a time.
> +
> +Please read <linux/zio-trigger.h> together with this file.
> +
> +	Trigger Types
> +	=============
> +
> +Triggers may be device-specific or generic. A few generic triggers
> +are part of zio-core. The "app-request" trigger fires input when
> +the application calls read and fires output when the application calls
> +write (it acts on a single channel). The "ktimer" trigger uses a kernel
> +timer as trigger source. The "irq" trigger uses any interrupt (e.g.,
> +a GPIO interrupt, or pin 10 of the PC parallel port) as trigger event.
> +
> +A device-specific trigger declares to be such within its attributes.  A
> +device-specific trigger can only be used by csets that declare its name
> +as preferred trigger type.  When such csets are registered, if the
> +trigger is already known to ZIO, it will be activated by default instead
> +of "app-request".
> +
> +	Trigger Operations
> +	==================
> +
> +Trigger operations are the following:
> +
> +	struct zio_ti *(*create)(struct zio_trigger_type *trig,
> +				 struct zio_cset *cset,
> +				 struct zio_control *ctrl,
> +				 fmode_t flags);
> +	void (*destroy)(struct zio_ti *ti);
> +
> +Create and destroy a trigger instance for a cset. ZIO calls create() when
> +attaching the trigger to a cset; it calls destroy() when the trigger is
> +replaced by a different one or the cset is being unregistered from ZIO.
> +The instance structure is trigger-specific, but it must include the
> +generic structure zio_ti. Every time this structure is passed over, trigger
> +code may use container_of if it needs to access the private enclosing
> +structure.
> +
> +	int (*config)(struct zio_ti *ti, stuct zio_control *ctrl);
> +
> +The method is called by ZIO whenever the attributes for a trigger
> +instance are modified by the user (by writing to sysfs or otherwise).
> +
> +	int (*push_block)(struct zio_ti *ti,
> +			  struct zio_channel *chan,
> +			  struct zio_control *ctrl);
> +
> +This is used for output channels: when a new data block is ready, it
> +must be sent to the trigger so it can be output when the event fires.
> +Buffer code, therefore, is expected to call this trigger method.  The
> +function can return -EAGAIN if it has no space in the queue, or 0 on
> +success. If EAGAIN happens, the buffer should handle it (by storing
> +locally or notifying the user).
> +
> +	void (*pull_block)(struct zio_ti *ti,
> +	  		   struct zio_channel *chan);
> +
> +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 of storing a block

                                                  for storing

> +when available.  Since driver->input_cset 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.
> +
> +        void (*data_done)(struct zio_cset *cset);
> +
> +The function is called by the device, and signals the trigger that
> +the input or output operation on the cset is over. For input, the
> +trigger will push blocks to the buffer, for output it will release

                                   buffer; for

> +the blocks.  zio-core offers zio_generic_data_done() for triggers
> +that don't need special handling.
> +
> +	File Operations
> +	===============
> +
> +The trigger may include a non-NULL f_ops pointer. Most triggers will
> +not need it, but for example "app-request" does, because it needs to
> +look at individual read and write calls performed by applications.
> +ZIO will use these file operations (instead of the buffer file operations)
> +when the open method of the char device detects that the active trigger
> +declares a non-NULL f_ops field.  These operations will most
> +likely fall back to buffer->f_ops for most of their actual work.
> +
> +See zio-trig-app-request.c for details about how this is used.
> +
> +	When the trigger fires
> +	======================
> +
> +The trigger event may happen for a variety of reasons. It can be
> +time-driven, data-driven or whatever else.  In any case, there is
> +a time when the trigger fires, so input or output may happen.
> +(With most hardware-specific triggers, the actual input or output of
> +data has already happened when the trigger interrupt runs, but this
> +doesn't change the software flow).
> +
> +Hardware-driven triggers will need to make their own work by themselves,
> +but ZIO offers this help macro to loop over all non-disabled channels:

                       helper macro

> +
> +	cset_for_each(struct zio_cset *cset, struct zio_channel *ch)
> +
> +The macro works like "task_for_each" or "list_for_each" in the kernel
> +headers.
> +
> +For software-based triggers (where actual I/O happens when software
> +wants it to happen, even if it is in response to an interrupt), the
> +asynchronous code that runs the event will just need to call
> +
> +	zio_fire_trigger(struct zio_ti *ti);
> +
> +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.
> +
> +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
> +implementation based on trigger-local file_operations.
> +

Drop last blank line.

> diff --git a/drivers/zio/README b/drivers/zio/README
> new file mode 100644
> index 0000000..d537353
> --- /dev/null
> +++ b/drivers/zio/README

I'd prefer to see this file in Documentation/zio/ with the other doc files.

> @@ -0,0 +1,105 @@
> +
> +Zio is "the ultimate I/O framework".  Is being developed on the open

                                         It is being

> +hardware repository at http://www.ohwr.org/projects/zio .
> +
> +This version is known to compile and run with kernels 2.6.34 onwards.
> +
> +This README refers to version "beta3", but work is ongoing towards
> +a stable package. See the TODO file on ohwr for details.
> +
> +To test zio you need to load the core modules (later, the default
> +trigger and default buffer will be part of zio-core):
> +
> +   	insmod zio-core.ko
> +   	insmod buffers/zio-buf-kmalloc.ko
> +   	insmod triggers/zio-trig-timer.ko
> +
> +Drivers can't live without a trigger and a buffer, so the modules above
> +must be loaded first.
> +
> +The kmalloc buffer is a simple buffer that hosts a list of data blocks,
> +for either input or output.
> +
> +The timer trigger is a kernel-timer based trigger, that fires a block
> +transfer on a timely basis. You can use the "ms" parameter to set the
> +inter-block time, in milliseconds (the default is two seconds). You
> +can also pass the "nsamples" parameter to say how many samples are
> +aquired at each trigger instance.

   acquired

> +
> +With the core in place, you can load a driver:
> +
> +	insmod drivers/zio-zero.ko
> +
> +zio-zero has a single channel-set (number 0) with three channels.
> +They simulate three analog inputs, 8-bit per sample.

                                      8 bits per sample.

> +
> +     channel 0: returns zero forever
> +     channel 1: returns random numbers
> +     channel 2: returns a sawtooth signal (0 to 255 and back)
> +
> +The char devices are called using device-cset-channel:
> +
> +    /dev/zzero-0-0-ctrl
> +    /dev/zzero-0-0-data
> +    /dev/zzero-0-1-ctrl
> +    /dev/zzero-0-1-data
> +    /dev/zzero-0-2-ctrl
> +    /dev/zzero-0-2-data
> +
> +(later versions will use a /dev/zio/ directory for all zio files)
> +
> +To read data you can just cat, or "od -t x1" the data device.
> +To get control information meta-information) together with data, you
> +can use the "zio-dump" user-space utility, in this directory.
> +
> +For example:
> +
> +    ./zio-dump /dev/zzero-0-2-ctrl /dev/zzero-0-2-data
> +
> +This is the result with a trigger that uses 2000 as msec and 32
> +as nsample:
> +
> +    ./zio-dump /dev/zzero-0-2-ctrl /dev/zzero-0-2-data
> +
> +    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 2
> +    Ctrl: seq 1, n 32, size 1, bits 8, flags 01000001 (little-endian)
> +    Ctrl: stamp 1320403540.084798370 (0)
> +    Data: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
> +    Data: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
> +
> +    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 2
> +    Ctrl: seq 2, n 32, size 1, bits 8, flags 01000001 (little-endian)
> +    Ctrl: stamp 1320403542.091093781 (0)
> +    Data: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
> +    Data: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
> +
> +    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 2
> +    Ctrl: seq 3, n 32, size 1, bits 8, flags 01000001 (little-endian)
> +    Ctrl: stamp 1320403544.084790274 (0)
> +    Data: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
> +    Data: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
> +
> +Zio dump is able to access several pairs of devices (control and data),

   zio-dump

> +and you can change the trigger and buffer attributes for the cset.
> +
> +Example:
> +
> +    echo 500 > /sys/zio/devices/zzero/cset0/trigger/ms-period
> +    echo 4 > /sys/zio/devices/zzero/cset0/trigger/nsamples
> +    echo 3 > /sys/zio/devices/zzero/cset0/chan0/buffer/max-buffer-len
> +    ./zio-dump /dev/zzero-0-*
> +
> +    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 0
> +    Ctrl: seq 102, n 4, size 1, bits 8, flags 01000001 (little-endian)
> +    Ctrl: stamp 4066.519285605 (0)
> +    Data: 00 00 00 00
> +
> +    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 1
> +    Ctrl: seq 102, n 4, size 1, bits 8, flags 01000001 (little-endian)
> +    Ctrl: stamp 4066.519285605 (0)
> +    Data: 71 29 a6 53
> +
> +    Ctrl: version 0.2, trigger timer, dev zzero, cset 0, chan 2
> +    Ctrl: seq 102, n 4, size 1, bits 8, flags 01000001 (little-endian)
> +    Ctrl: stamp 4066.519285605 (0)
> +    Data: 60 61 62 63


-- 
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2011-12-06  4:13 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-26 17:30 [RFC PATCH 0/7] Introducing ZIO, a new I/O framework Alessandro Rubini
2011-11-26 17:30 ` [RFC PATCH 1/7] Documentation: add docs for drivers/zio Alessandro Rubini
2011-11-26 20:00   ` Greg KH
2011-11-26 21:48     ` Federico Vaga
2011-11-26 22:16   ` Jonathan Cameron
2011-11-26 22:53   ` Alessandro Rubini
2011-12-06  5:12   ` Randy Dunlap
2011-11-26 17:30 ` [RFC PATCH 2/7] include/linux: add headers " Alessandro Rubini
2011-11-26 20:02   ` Greg KH
2011-11-26 21:46     ` Federico Vaga
2011-11-27  9:32       ` Greg KH
2011-11-28 14:56         ` Federico Vaga
2011-11-30  6:21           ` Greg KH
2011-11-26 17:30 ` [RFC PATCH 3/7] drivers/zio: core files for the ZIO input/output Alessandro Rubini
2011-11-26 20:03   ` Greg KH
2011-11-26 22:58     ` Federico Vaga
2011-11-27  9:33       ` Greg KH
2011-11-28 14:59         ` Federico Vaga
2011-11-26 17:30 ` [RFC PATCH 4/7] drivers/zio: add triggers and buffers Alessandro Rubini
2011-11-26 17:31 ` [RFC PATCH 5/7] drivers/zio: add the zio-zero device driver Alessandro Rubini
2011-11-26 17:31 ` [RFC PATCH 6/7] drivers/zio: add user-space tool zio-dump Alessandro Rubini
2011-11-26 17:31 ` [RFC PATCH 7/7] zio: insert in Kbuild so it is actually compiled Alessandro Rubini
2011-11-26 18:09 ` [RFC PATCH 0/7] Introducing ZIO, a new I/O framework Lars-Peter Clausen
2011-11-26 19:11 ` Alessandro Rubini
2011-12-01 21:41   ` Linus Walleij

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).