Commit 50077861 authored by Alessandro Rubini's avatar Alessandro Rubini

Documentation/zio: removed (we have doc/ already)

Some of the information in there was old, and we should rather extract
the files in Documentaion/zio/ from the doc/zio-manual.txt .
Currently, just remove the old information.

Please, users, read material in doc/ instead (or the pdf on ohwr.org).
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
Acked-by: 's avatarFederico Vaga <federico.vaga@gmail.com>
parent 59d8d443
00-INDEX
- this file
device.txt
- description of what ZIO devices (and csets and channels) are.
buffer.txt
- description of the buffer, its methods and how it is used.
trigger.txt
- what is a trigger and what's its role in ZIO.
sysfs.txt
- description of how ZIO uses sysfs
modules.txt
- list of modules (and description) found in the first ZIO package
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);
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 returns 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. create() can use default attributes of its buffer type at
creation time; a copy for this specific instance is created by
zio-core after the function returns. A failed creation must return
ERR_PTR(-ENOMEM) or similar.
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,
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 information. 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. A failed
allocation returns NULL.
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 structure holds 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 may not. See zio-buf-kmalloc.c for a working example of
buffer file operations.
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 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.
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 directory for an example
of a generic and simple input application that shows use of control and
data files.
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.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
"user".
drivers/zio/trigger/zio-trig-timer.ko
drivers/zio/trigger/zio-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/drivers/zio-zero.ko
drivers/zio/drivers/zio-gpio.ko
drivers/zio/drivers/zio-ad788x.ko
These modules are examples. The zero driver is an emulator of an
input/output device. It can be used to experiment with generic
triggers and as a sandbox for local modifications and testing.
It has 4 input channels and 1 output channel. Each of the 4 input
channel generates a particular waveform: a flat signal (zero), a white
noise signal, saw-tooth and a sequence of 32-bit little-endian numbers.
The last signal can be used for diagnostics and regression testing of
buffers. The output channel discards all samples.
The gpio driver register two single-channel csets: one for input the
other for output. The user specifies (on driver load, as module parameter)
which GPIOs use for input and which ones for output.
The ad788x driver handle two devices: the ad7887 and the ad7888.
Both devices are SPI ADC we mounted on an ARM board; ad788 is a
8-channel ADC and ad7887 is a 2-channel ADC with variable voltage
reference. We are using these devices 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).
Spinlocks
=========
zio_status->lock
----------------
ZIO takes track of all registered devices, csets, trigger types and
buffer types with a list for each object. When you add or remove an
element from these lists, alock must be taken. These lists can be
modified only during registration and unregistration operations,
nowhere else.
zio_device->lock
----------------
This lock is used to serialize every configuration operation performed
through zio attributes. Independently from which ZIO object is the
owner of the ZIO attribute, the correspondent zio_device lock is taken:
zio_device->lock
zio_cset->zdev->lock
zio_channel->cset->zdev->lock
zio_ti->cset->zdev->lock
zio_bi->cset->zdev->lock
Device, buffer and trigger are registered as different objects but
are usually on the same peripheral; so, registers which correspond to
zio attributes are all on the same peripheral. If buffer or trigger
are not on the same peripheral of device, it is usally because are software
implementation, then taking the zio_device->lock still works. In the
rare case where buffer or trigger are not on the same peripheral of
device and they are not software implemented and they can be shared with
other devices, then, you must handle concurrency within your drivers.
This lock is also used to protect the enable status of device, cset,
channel and trigger instance. When one of these element change its
status, no one else can change its status or modify any zio attributes.
In this case the trigger operations abort() and change_status() run in a
locked contest.
zio_cset->lock
--------------
This lock is used to protect the concurrent access to transfer
informations such as: ti->flags ZTI_STATUS bit
zio_bi->lock
------------
zio_ti->lock
------------
/* FIXME useless ?*/
zio_buffer_type->lock and zio_trigger_type->lock
---------------------
Both types take track of every instances created with a list. When a
new instance is added or removed from its list, the correspondent
lock must be taken. ZIO modifies these list only during registration
and unregistration of the correspondent instance.
zio_attribute
=============
The main idea behind the zio_attribute is that generally what is a
sysfs attribute is also a register in a I/O peripheral; ZIO attributes
can thus be used to export to the host system the device internal
registers. ZIO uses a pair of numbers: address and value. The address
represents the way to gain access to a device register; it is an union
of two elements: addr which is the register address, and ptr which is
a pointer to a private structure defined within the low-level driver;
the driver implementor can choose whether to use an address alone or
allocate its own private structure.
struct zio_attribute {
struct attribute attr;
uint32_t flags;
int index;
union {
void *ptr;
unsigned long addr;
} priv;
uint32_t value;
const struct zio_sysfs_operations *s_op;
};
ZIO sysfs Operations
====================
ZIO uses two sysfs operations: conf_set() and info_get(); the former
writes a configuration value to a register and the latter retrieves a
value from a register.
The ZIO core takes care of ASCII conversion between ZIO and sysfs
because ZIO attributes must all be integer values. ZIO also ensures
that access to info_get and conf_set is serialized, by using spinlocks
at device scope.
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);
ZIO calls the conf_set operation every time a user changes an attribute
value. Drivers can avoid defining info_get if the attributes are only
changed by the user. If values may change for other reasons (for
example to reflect internal device status), you must implement info_get
to re-syncronize the ZIO attribute value with the register value. When
the info_get method is not implemented, ZIO returns the current value
of the attribute.
Attribute Classification
========================
ZIO classifies its own sysfs attributes in two categories: standard
and extended.
Standard Attributes
-------------------
Standard attributes are the most common attributes among I/O
peripherals; for example gain, offset, sample-rate. The main feature
of a standard attribute is that its name in sysfs and its meaning are
clearly defined, irrespective of the peculiarities of the individual
device. Standard attributes are not mandatory, so each object
declares which one within the standard set apply to itself.
Within standard ZIO attributes, all times (such as delay and sample
period) are represented as nanoseconds, all voltages (such as range or
trigger value) are represented as microvolts. Special needs (such as
picoseconds or nanovolts) may be handled in extended attributes.
Following the list of the current standard attributes:
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_TRIG_REENABLE /* re-arm trigger */
ZATTR_TRIG_PRE_SAMP, /* samples before trigger fire */
ZATTR_TRIG_POST_SAMP, /* samples after trigger fire */
ZATTR_ZBUF_MAXLEN /* max number of element in buffer */
Extended Attributes
-------------------
Extended attributes are object-specific. They are defined to
cater for unique device features that cannot be generalized to a
framework-wide abstraction. Each extended attribute has a different
name defined by developer, and its meaning is not the same among the
set of I/O peripherals or conf_set implementations.
Attribute Set
-------------
All ZIO objects (devices, triggers and buffers) have standard and
extended attributes which are part of the zio_attribute_set container.
struct zio_attribute_set {
struct zio_attribute *std_zattr;
unsigned int n_std_attr;
struct zio_attribute *ext_zattr;
unsigned int n_ext_attr;
struct attribute_group group;
};
The ZIO attribute-set defines the ZIO standard attributes and the
extended ones. In order to register attributes within the
sysfs file system, the code needs to pass an attribute_group
How define a ZIO attribute
============================
Each zio object (device, buffer and trigger) can define its own zio
attribute. In order to define a new zio attribute (standard or
extended), the zio framework provides some macros. The following
macro:
DEFINE_ZATTR_STD(_type, _name)
must be used to declare a new set of standard attributes; _type is
used to specify the kind of zio object, _name is the name of the
array of standard attributes. The following macros are used to
define each single attributes:
ZATTR_REG(zobj, _type, _mode, _add, _val)
ZATTR_PRV(zobj, _type, _mode, _priv, _val)
ZATTR_EXT_REG(_name, _mode, _add, _val)
ZATTR_EXT_PRV(_name, _mode, _priv, _val)
Where:
_val: is the default value of the zio attribute (the
register on the peripheral)
_add: is the address to gain access to the physical
register
_priv: is a pointer to a private structure to use to gain
access to the physical register
_mode: is the permission mask for the sysfs file
_name: is the name shown in sysfs
_type: is the type of standard attribute
_zobj: is the kind of zio object
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.
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 "user" trigger fires input when
the application calls read and fires output when the application calls
write. The "timer" 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 "user".
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 for storing a block
when available. Since cset->raw_io completes asynchronously, this
method can't return a block directly. The block that will be stored
may be shorter than what the trigger would have stored in the buffer
by itself.
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.
void (*abort)(struct zio_cset *cset);
This function is called to stop a running acquisition before the data_done
invocation. ZIO calls this function when a trigger is disabled during a
data transfer. The abort function has two choice: it can invoke data_done
and return partial blocks, or free all the active blocks.
void (*change_status)(struct zio_ti *ti, unsigned int status);
ZIO invokes this function each time user enable or disable the trigger. The
status value is the new status of the trigger: 0 for disable and 1 for enable.
The function activates or deactivates the trigger depending on status. If the
trigger is running and the user disable it before the data_done, ZIO calls
sequentially abort and then change_status.
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 helper macro to loop over all non-disabled channels:
chan_for_each(struct zio_channel *ch, struct zio_cset *cset)
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 cset->raw_io is called.
You can refer to "zio-trig-timer" for an example of a multi-instance
generic timer and to "zio-trig-app-request" for a non-conventional
implementation based on trigger-local file_operations.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment