From: Jonathan Cameron <[EMAIL PROTECTED]>

A very early cut of some documentation for the industrialio subsystem. Also
includes a small demo app for listening to a ring buffer event chrdev and
reading from the access chrdev as appropriate.
--- a/Documentation/industrialio/overview.txt   1970-01-01 01:00:00.000000000 
+0100
+++ b/Documentation/industrialio/overview.txt   2008-07-24 18:37:56.000000000 
+0100
@@ -0,0 +1,117 @@
+Overview of the industrialio subsystem.
+
+Main Components
+
+Core
+
+industrialio-core.c contains the main registration code for devices using the
+subsytem. The key function is
+
+int iio_device_register(struct iio_dev *dev_info);
+
+This takes a structure containing a number of user specified variables which
+control how the device driver interacts with the subsystem components.
+
+This is a cut down version containing only those elements intended for direct
+access by drivers.
+
+struct iio_dev {
+/* device specific data */
+       void *dev_data;
+
+/* Modes the drivers supports */
+       int modes;
+
+/* Current mode */
+       int currentmode;
+
+/* The device for with which we are dealing */
+       struct device *dev;
+
+/* General attributes */
+       const struct attribute_group *attrs;
+
+/* Used to specify ownership of interrupt etc that may be created by iio */
+       struct module *driver_module;
+/* How many hardware interrupt lines are there */
+       int num_interrupt_lines;
+
+/* Event control attributes */
+       struct attribute_group *event_attrs;
+
+
+/* Software Ring Buffer (discussed in iio_ring.txt
+   - for now assuming only makes sense to have a single ring */
+       int ring_dimension;
+       int ring_bytes_per_datum;
+       int ring_length;
+
+/* enabling / disabling related functions.
+ * post / pre refer to relative to the change of current_mode. */
+       int (*ring_preenable)(struct iio_dev *);
+       int (*ring_postenable)(struct iio_dev *);
+       int (*ring_predisable)(struct iio_dev *);
+       int (*ring_postdisable)(struct iio_dev *);
+
+       void (*ring_poll_func)(void *private_data);
+
+       /* Device state lock.
+        * Used to prevent simultaneous changes to device state.
+        * In here rather than modules as some ring buffer changes must occur
+        * with this locked.*/
+       struct mutex                    mlock;
+
+};
+
[EMAIL PROTECTED] - driver specific data.
+
[EMAIL PROTECTED] - currently limited to combinations of INDIO_DIRECT_MODE,
+INDIO_RING_POLLED, INDIO_RING_DATA_RDY and INDIO_RING_HARDWARE_BUFFER
+
+All devices should probably support INDIO_DIRECT_MODE which means
+that sensor values may be read directly from files in sysfs.
+Typically this may be via single element files (x, y, z for accelerometers)
+or scan files (max1363 for example).
+
+INDIO_RING_POLLED currently uses periodic real time clocks to generate
+interrupts which are then used to poll the device. See iio_ring for more 
details
+
+INDIO_RING_DATA_RDY is for devices that supply a data ready interrupt when new
+data becomes available (eg lis3l02dq)
+
+INDIO_RING_HARDWARE_BUFFER is for devices with hardware ring buffers
+(eg. sca3000)
+
[EMAIL PROTECTED] general attribute group for both direct access attributes for 
reading
+from sensors and for sensor specific parameters of use to userspace (conversion
+factors etc).
+
[EMAIL PROTECTED] - corresponds to OWNER within the driver.  This is to ensure
+any interrupts etc requested are registered to the relevant module rather than
+iio.
+
[EMAIL PROTECTED] - does what it says on the tin.  Most devices only have one
+but I have seen ones with separate lines for data ready signals from motion
+detection etc.
+
[EMAIL PROTECTED] - sysfs attributes which control whether particular events 
(read
+interrupts from the point of view of the sensor) are enabled or not.  If they
+are up to 10 events will be queued on the related chrdev for reading by
+userspace code.
+
+Ring parameters and functions are covered in iio_ring.txt.
+
[EMAIL PROTECTED] - device configuration lock. Note it is the responsibility of 
drivers
+to get this lock if they wish to change parameters which may effect ring buffer
+capture (changing scan modes for example.)
+
+
+What happens when a iio_dev is registered.
+
+1) Unique id obtained.
+2) Sysfs direct read and configuration elements registered
+3) Device event (sensor interrupts) registered.
+4) If software ring to be used, setup the ring but don't actually allocate.
+   This occurs on first enabled / when reenabled after parameter change.
+4) If polled ring get a periodic timer.
+

--- a/Documentation/industrialio/iio_ring.txt   1970-01-01 01:00:00.000000000 
+0100
+++ b/Documentation/industrialio/iio_ring.txt   2008-07-24 18:45:04.000000000 
+0100
@@ -0,0 +1,91 @@
+Industrialio subsystem ring buffers
+
+The industrial io subsystem supports both hardware (eg. sca3000) and software
+(eg. max1363 and lis3l02dq) ring buffers.
+
+For both types a chrdev is used to provide events to userspace. These merely
+contain an id and a timestamp.
+
+This is used to provide notifications of the ring having reached a certain 
level
+(50%, 75%, 100%).
+
+Direct access to the contents of the ring buffer is available via a second
+dev. The data output is pretty much raw device readings, so a userspace 
function
+is needed to convert these into appropriate SI units.  This function should be
+provided in a device specific header if appropriate.
+
+The hardware ring buffer simply implements the above functionality by pull data
+directly from the device on demand (sca3000).
+
+
+The software ring buffer is somewhat more complex.
+
+The design considerations for this are:
+
+1) Writing should be as latency free as possible (preferably lock free)
+2) As few readings as possible should be missed (ideally none - but as
+   we aren't dealing with a realtime OS some will occasionally be lost).
+3) Reading does not lock the buffer but instead takes a copy then validate
+   what data is 'clean' approach.
+4) The filling of the buffer should be either driver by the device (datardy)
+   or if that is not possible via a periodic time source.
+5) All latencies should be as small as possible(wishful thinking ;)
+
+The code in industrialio-ring.c meets most of these requirements and hopefuly
+does not have any critical failure cases.
+
+A number of pointers into a static array are maintained.
+
+write_p - the next location to write to.
+read_p - the oldest location from which we may read (start point for copying)
+last_written_p - the newest location from which we may read (used to provide
+              direct access whilst the ring buffer is in use, without adding
+              to the communications with the sensor.
+
+half_p - Kept half the length of the buffer behind the write pointer and used
+       in conjunction with read_p to trigger an event when the buffer is half
+       full.
+
+The events are designed to escalate until we reach the point of buffer 100%
+full. Thus a single event has it's code changed when it becomes outdated.
+
+
+The other interesting bit is reading data from the ring. Currently this is via
+normal file reads rather than mmaping the ring buffer.
+
+1) A copy of the ring buffer between read_p and write_p is made.  This is done
+without locking the buffer in anyway so the data is not guaranteed to have not
+been changed by subsequent writes.
+
+2) The value of read_p after the copy is used to provide a worst case location
+for where we have clean data from.  There is an obvious nasty case of the read
+pointer having wrapped all the way round the buffer. For now we assume the
+capture rate is slow enough that this will not have happened.
+
+Only the valid data is then sent to userspace.
+
+
+What the iio_dev ring parameters are
+
[EMAIL PROTECTED] Number of bytes per 'reading', this includes timestamp
+
[EMAIL PROTECTED] Number of readings in the ring
+
+The four functions are concerned with behaviour around the point where the
+device mode actually switches.
[EMAIL PROTECTED] - usually things like disabling unwanted (sensor side)
+               interrupts.
+
[EMAIL PROTECTED] - usually actually enabling the data ready generation if
+                appropriate.
+
[EMAIL PROTECTED] - usually disabling data ready generation
[EMAIL PROTECTED] - restoring anything disable before the the ring came into
+                 use.
+
[EMAIL PROTECTED] - For perioidic timer based rings, this function is called on
+               each timer interrupt. Reads from the device and pushes the
+               data into the ring. Also tends to grab a timestamp at the
+               point likely to be as close as possible to when the data
+               was acquired. Sensor specific offsets can compensate for
+               some fixed lags (particularly at low bus speeds).
--- a/Documentation/industrialio/TestRingMax1363.c      1970-01-01 
01:00:00.000000000 +0100
+++ b/Documentation/industrialio/TestRingMax1363.c      2008-07-24 
18:48:56.000000000 +0100
@@ -0,0 +1,106 @@
+/* Industrialio test ring buffer with a max1238
+ *
+ * Copyright (c) 2008 Jonathan Cameron
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ * Little tool to poke character devices associated with ring buffer and see
+ * what events are coming out.
+ *
+ * Todo: Make this more adapatable - e.g. allow specification of which
+ *       ring to poke.
+ *
+ * Clearly this needs a lot of work if it going to be a coherent / general
+ * piece of example code.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <linux/types.h>
+
+
+struct iio_event_data {
+       int id;
+       __s64 timestamp;
+};
+int main(int argc, char **argv)
+{
+       FILE  *sysfsfp, *fp_ev;
+       int fp;
+       char data[20000];
+       size_t read_size;
+       int i, j, k;
+       int minor, minor_ev;
+       char name[100];
+       char name2[100];
+       char command[100];
+       char temp[100];
+       int pos;
+       struct iio_event_data dat;
+       int device_no;
+
+       if (argc == 1)
+               return -1;
+       device_no = atoi(argv[1]);
+       pos = sprintf(temp, "/sys/class/industrialio/industrialio%d/device/",
+                     device_no);
+       sprintf(temp + pos, "ring_buffer0_access_minor");
+       sysfsfp = fopen(temp, "r");
+       if (sysfsfp == NULL) {
+               printf("failed to open minor stuff \n");
+               return -1;
+       }
+
+       fscanf(sysfsfp, "%d\n", &minor);
+       sprintf(name, "/dev/indring%d", minor);
+
+       fclose(sysfsfp);
+       sprintf(temp + pos, "ring_buffer0_ev_minor");
+       sysfsfp = fopen(temp, "r");
+       if (sysfsfp == NULL) {
+               printf("failed to open minor stuff \n");
+               return -1;
+       }
+
+       fscanf(sysfsfp, "%d\n", &minor_ev);
+       fclose(sysfsfp);
+       sprintf(name2, "/dev/indringev%d", minor_ev);
+
+       fp = open(name, O_RDONLY | O_NONBLOCK);
+       if (fp == -1) {
+               sprintf(command, "mknod %s c 244 %d; mknod %s c 244 %d ",
+                       name, minor, name2, minor_ev);
+               system(command);
+               fp = open(name, O_RDONLY | O_NONBLOCK);
+               if (fp == -1) {
+                       printf("Unable to open %s\n", name);
+                       return -1;
+               }
+       }
+       fp_ev = fopen(name2, "rb");
+       if (fp_ev == NULL)
+               printf("bug opening %s\n", name2);
+       /* Wait for events 10 times */
+       for (j = 0; j < 10; j++) {
+               read_size = fread(&dat, 1, sizeof(struct iio_event_data),
+                                 fp_ev);
+               printf("event code received: %d\n", dat.id);
+               read_size = read(fp, (char *)(data), 100*(12+8));
+               if (read_size == -EAGAIN)
+                       printf("nothing available \n");
+
+               /* print a small amount of data */
+               for (i = 0; i < 10; i++) {
+                       for (k = 0; k < 12; k++)
+                               printf("%d ",
+                                      ((int)((data[i*32 + (k)*2 + 0]
+                                              & 0x0F) << 8)
+                                       + ((int)((data[i*32 + (k)*2 + 1])))));
+                       printf(" %lld\n", *(__s64 *)(&data[i*32 + 12*2]));
+               }
+       }
+       return 0;
+}

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
spi-devel-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

Reply via email to