diff --git a/Documentation/zio/00-INDEX b/Documentation/zio/00-INDEX new file mode 100644 index 0000000000000000000000000000000000000000..f5106951554fce07515ef38a7a378c127bf305df --- /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. +tools/ + - useful and simple user-space programs \ No newline at end of file diff --git a/Documentation/zio/buffer.txt b/Documentation/zio/buffer.txt new file mode 100644 index 0000000000000000000000000000000000000000..294fedde141c9e0bbca86a47b5b18801b2165bde --- /dev/null +++ b/Documentation/zio/buffer.txt @@ -0,0 +1,106 @@ + +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 +of control and 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 will 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: + + void *(*create)(struct zio_buffer *buffer, struct zio_channel *ch, + fmode_t f_flags); + void (*destroy)(void *b_instance); + +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 instance is a void pointer because each buffer needs a +different (private) data structure to represent an own instance. + +Destroy deallocates the buffer. 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. + + void *(*alloc_block)(void *b_instance, void **handle_ret, + size_t size, gfp_t gfp); + void (*free_block)(void *handle); + +For input channels, a block is allocated when the trigger fills it, +and it is freed when user has read or ignored it. For output, +allocation happens on user write and free is called by the trigger. +Thus, the function are sometimes called by buffer code itself, and +sometimes by the trigger. The data structure hosting a block is +returned as a void pointer because each buffer needs its own +private structure. + + ssize_t (*store_block)(void *handle, struct zio_control *ctrl, + void *data, size_t len); + ssize_t (*retr_block) (void *handle, struct zio_control *ctrl, + void *data, size_t len); + +The trigger calls the store method when it has data to push for input +channels. If uses an handle it received from the alloc_block method. +The trigger for output channels uses the retrieve method to extract +data from the buffer and send it to the hardware driver. After +retrieving data, it is responsible for freeing it. +FIXME: how can the trigger know the handle to retrieve? + + + File Operations + =============== + +These are the file_operations used by the char devices (control and +data) for every channel using this buffer type. The open method of +the zio file operations kmallocs f->private_data to point to this +structure: + + struct zio_f_priv { + void *b_instance; + enum zio_cdev_type type; + }; + +All buffer file operations can thus refer to the buffer instance for +this channel and know if the current file is ZIO_CDEV_CTRL or +ZIO_CDEV_DATA. The release file operation is expected to free this +structure. + +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 0000000000000000000000000000000000000000..75bd1028f6d9d0a9ba5d83525a27958645bd491b --- /dev/null +++ b/Documentation/zio/device.txt @@ -0,0 +1,68 @@ + + 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 tools/zio-dump.c for an example of generic and simple input +application that shows use of control and data files. + + diff --git a/Documentation/zio/tools/zio-dump.c b/Documentation/zio/tools/zio-dump.c new file mode 100644 index 0000000000000000000000000000000000000000..b9b81e8ccbac426d475710538d64953515f473a5 --- /dev/null +++ b/Documentation/zio/tools/zio-dump.c @@ -0,0 +1,128 @@ +/* + * 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 "zio.h" +#include "zio-buffer.h" + +#define FD_C 0 +#define FD_D 1 + +unsigned char buf[1024*1024]; + +int main(int argc, char **argv) +{ + FILE *f; + char *outfname; + int fd[2]; + int i, j; + + if (argc !=3) { + fprintf(stderr, "%s: use \"%s <ctrl-file> <data-file>\"\n", + argv[0], argv[0]); + exit(1); + } + + for (i = 0; i < 2; i++) { + fd[i] = open(argv[i + 1], O_RDONLY); + if (fd[i] < 0) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i + 1], + strerror(errno)); + exit(1); + } + } + /* the data channel is non-blocking */ + fcntl(fd[FD_D], F_SETFL, fcntl(fd[FD_D], F_GETFL) | O_NONBLOCK); + + /* 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", argv[0], outfname, + strerror(errno)); + exit(1); + } + /* ensure proper strace information and output to pipes */ + setlinebuf(stdout); + setbuf(f, NULL); + + /* now read control and data, forever */ + while (1) { + zio_control_t ctrl; + + /* This is a blocking read to the control file */ + i = read(fd[FD_C], &ctrl, sizeof(ctrl)); + switch(i) { + case -1: + fprintf(stderr, "%s: %s: read(): %s\n", + argv[0], argv[1 + FD_C], strerror(errno)); + exit(1); + case 0: + fprintf(stderr, "%s: %s: unexpected EOF\n", + argv[0], argv[1 + FD_C], strerror(errno)); + exit(1); + default: + fprintf(stderr, "%s: ctrl: read %i bytes (exp %i)\n", + argv[0], i, sizeof(ctrl)); + /* continue anyways */ + case sizeof(ctrl): + break; /* ok */ + } + printf("Ctrl: n %i, size %i, bits %i, flags %08x\n", + ctrl.ctrl.nsamples, + ctrl.ctrl.ssize, + ctrl.ctrl.sbits, + ctrl.ctrl.flags); + printf("Ctrl: stamp %li.%09li (%lli)\n", + ctrl.ctrl.tstamp.tv_sec, + ctrl.ctrl.tstamp.tv_nsec, + ctrl.ctrl.tstamp_extra); + /* FIXME: some control information is missing */ + + i = read(fd[FD_D], buf, sizeof(buf)); + if (i < 0) { + fprintf(stderr, "%s: %s: read(): %s\n", + argv[0], argv[1 + FD_D], strerror(errno)); + continue; /* next ctrl, let's see... */ + } + if (!i) { + fprintf(stderr, "%s: %s: unexpected EOF\n", + argv[0], argv[1 + FD_D], strerror(errno)); + continue; + } + if (i != ctrl.ctrl.nsamples * ctrl.ctrl.ssize) { + if (i == sizeof(buf)) { + fprintf(stderr, "%s: buffer too small\n", + argv[0]); + /* FIXME: empty the data channel */ + } else { + fprintf(stderr, "%s: ctrl: read %i bytes " + "(exp %i)\n", argv[0], i, + ctrl.ctrl.nsamples * ctrl.ctrl.ssize); + } + /* continue anyways */ + } + fwrite(buf, 1, i, f); + + /* 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'); + } +} diff --git a/Documentation/zio/trigger.txt b/Documentation/zio/trigger.txt new file mode 100644 index 0000000000000000000000000000000000000000..491d59b393304ae10e75aea6c54106bda0c39e16 --- /dev/null +++ b/Documentation/zio/trigger.txt @@ -0,0 +1,125 @@ + +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. + + + 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 + ================== + +(NOTE: this is still subject to fine-tuning, as we are still writing code) + +Trigger operations are the following: + + struct zio_trigger_instance *(*create)(struct zio_buffer *buffer, + struct zio_cset *cset); + void (*destroy)(struct zio_trigger_instance *t_instance); + +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 this +generic structure: + + struct zio_trigger_instance { + struct zio_trigger *trig; + struct zio_cset *cset; + }; + +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_trigger_instance *t_instance); + +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 (*enqueue_block)(struct zio_trigger_instance *t_instance, + struct zio_channel *ch, + struct zio_control *ctrl, + void *data, size_t len); + +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). + + int (*space_in_buffer)(struct zio_trigger_instance *t_instance); + +The method return either 0 (there is space for one block), a positive +value (the maximum size of the next block that can be enqueued) or +-EAGAIN. This can be used by the poll file operation, to ask +whether the next write(2) will succeed or not. + + File Operations + =============== + +The trigger may include a non-NULL f_ops pointer. Most trigger 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). + +For output triggers, the trigger instance is already hosting the data +blocks (received through the enqueue_block method), so the code will +just loop over all the channels and free such data blocks. In some cases +the trigger will need to perform the output before freeing data, in +most cases data has been prepared for DMA during enqueue_block, +so output already happened when the trigger run. + +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 input triggers, the asynchronous code that runs the event will just +need to call + + zio_fire_trigger(struct zio_trigger_instance *instance); + +This function, part of zio-core, internally runs "cset_for_each". +For each non-disabled channel, it calls the drv->input_block method +and the stores it in the active buffer. + +You can refer to "zio-trig-ktimer" 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. +