Re: [RFC PATCH 1/7] Documentation: add docs for drivers/zio

Randy Dunlap
2011-12-06T04:13:35Z

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 ***