Loading drivers/staging/iio/Documentation/device.txt 0 → 100644 +49 −0 Original line number Diff line number Diff line IIO Device drivers This is not intended to provide a comprehensive guide to writing an IIO device driver. For further information see the drivers within the subsystem. The crucial structure for device drivers in iio is iio_dev. First allocate one using: struct iio_dev *indio_dev = iio_allocate_device(); The fill in the following. indio_dev->dev.parent the struct device associated with the underlying hardware. indio_dev->num_interrupt_lines number of event triggering hardware lines the device has. indio_dev->event_attrs attributes used to enable / disable hardware events - note the attributes are embedded in iio_event_attr structures with an associated iio_event_handler which may or may note be shared. If num_interrupt_lines = 0, then no need to fill this in. indio_dev->attrs general attributes such as polled access to device channels. indio_dev->dev_data private device specific data. indio_dev->driver_module typically set to THIS_MODULE. Used to specify ownership of some iio created resources. indio_dev->modes whether direct access and / or ring buffer access is supported. Once these are set up, a call to iio_device_register(indio_dev), will register the device with the iio core. Worth noting here is that, if a ring buffer is to be used, it can be allocated prior to registering the device with the iio-core, but must be registered afterwards (otherwise the whole parentage of devices gets confused) On remove iio_device_unregister(indio_dev) will remove the device from the core, and iio_free_device will clean up. drivers/staging/iio/Documentation/iio_utils.h 0 → 100644 +159 −0 Original line number Diff line number Diff line /* IIO - useful set of util functionality * * 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. */ #define IIO_EVENT_CODE_RING_50_FULL 200 #define IIO_EVENT_CODE_RING_75_FULL 201 #define IIO_EVENT_CODE_RING_100_FULL 202 struct iio_event_data { int id; __s64 timestamp; }; inline char *find_ring_subelement(const char *directory, const char *subelement) { DIR *dp; const struct dirent *ent; int pos; char temp[100]; char *returnstring; dp = opendir(directory); if (dp == NULL) { printf("could not directory: %s\n", directory); return NULL; } while (ent = readdir(dp), ent != NULL) { if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) { if (strncmp(ent->d_name, subelement, strlen(subelement)) == 0) { int length = sprintf(temp, "%s%s%s", directory, ent->d_name, "/"); returnstring = malloc(length+1); strncpy(returnstring, temp, length+1); return returnstring; } } } return 0; } char *find_type_by_name(const char *name, const char *type) { const char *iio_dir = "/sys/class/iio/"; const struct dirent *ent; int cnt, pos, pos2; FILE *nameFile; DIR *dp; char thisname[100]; char temp[100]; char *returnstring = NULL; struct stat Stat; pos = sprintf(temp, "%s", iio_dir); dp = opendir(iio_dir); if (dp == NULL) { printf("No industrialio devices available"); return NULL; } while (ent = readdir(dp), ent != NULL) { cnt++; /*reject . and .. */ if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) { /*make sure it isn't a trigger!*/ if (strncmp(ent->d_name, type, strlen(type)) == 0) { /* build full path to new file */ pos2 = pos + sprintf(temp + pos, "%s/", ent->d_name); sprintf(temp + pos2, "name"); printf("search location %s\n", temp); nameFile = fopen(temp, "r"); if (!nameFile) { sprintf(temp + pos2, "modalias", ent->d_name); nameFile = fopen(temp, "r"); if (!nameFile) { printf("Failed to find a name for device\n"); return NULL; } } fscanf(nameFile, "%s", thisname); if (strcmp(name, thisname) == 0) { returnstring = malloc(strlen(temp) + 1); sprintf(temp + pos2, ""); strcpy(returnstring, temp); return returnstring; } fclose(nameFile); } } } } int write_sysfs_int(char *filename, char *basedir, int val) { int ret; FILE *sysfsfp; char temp[100]; sprintf(temp, "%s%s", basedir, filename); sysfsfp = fopen(temp, "w"); if (sysfsfp == NULL) return -1; fprintf(sysfsfp, "%d", val); fclose(sysfsfp); return 0; } /** * write_sysfs_string_and_verify() - string write, readback and verify * @filename: name of file to write to * @basedir: the sysfs directory in which the file is to be found * @val: the string to write **/ int write_sysfs_string_and_verify(char *filename, char *basedir, char *val) { int ret; FILE *sysfsfp; char temp[100]; sprintf(temp, "%s%s", basedir, filename); sysfsfp = fopen(temp, "w"); if (sysfsfp == NULL) return -1; fprintf(sysfsfp, "%s", val); fclose(sysfsfp); sysfsfp = fopen(temp, "r"); if (sysfsfp == NULL) return -1; fscanf(sysfsfp, "%s", temp); if (strcmp(temp, val) != 0) { printf("Possible failure in string write %s to %s%s \n", val, basedir, filename); return -1; } return 0; } int read_sysfs_posint(char *filename, char *basedir) { int ret; FILE *sysfsfp; char temp[100]; sprintf(temp, "%s%s", basedir, filename); sysfsfp = fopen(temp, "r"); if (sysfsfp == NULL) return -1; fscanf(sysfsfp, "%d\n", &ret); fclose(sysfsfp); return ret; } drivers/staging/iio/Documentation/lis3l02dqbuffersimple.c 0 → 100644 +171 −0 Original line number Diff line number Diff line /* Industrialio test ring buffer with a lis3l02dq acceleromter * * 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. * * Assumes suitable udev rules are used to create the dev nodes as named here. */ #include <dirent.h> #include <fcntl.h> #include <stdio.h> #include <errno.h> #include <stdint.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/dir.h> #include <linux/types.h> #include <dirent.h> #include "iio_util.h" static const char *ring_access = "/dev/iio/lis3l02dq_ring_access"; static const char *ring_event = "/dev/iio/lis3l02dq_ring_event"; static const char *device_name = "lis3l02dq"; static const char *trigger_name = "lis3l02dq-dev0"; static int NumVals = 3; static int scan_ts = 1; static int RingLength = 128; /* * Could get this from ring bps, but only after starting the ring * which is a bit late for it to be useful */ int size_from_scanmode(int numVals, int timestamp) { if (numVals && timestamp) return 16; else if (timestamp) return 8; else return numVals*2; } int main(int argc, char **argv) { int i, j, k, toread; FILE *fp_ev; int fp; char *data; size_t read_size; struct iio_event_data dat; char *BaseDirectoryName, *TriggerDirectoryName, *RingBufferDirectoryName; BaseDirectoryName = find_type_by_name(device_name, "device"); if (BaseDirectoryName == NULL) { printf("Failed to find the %s \n", device_name); return -1; } TriggerDirectoryName = find_type_by_name(trigger_name, "trigger"); if (TriggerDirectoryName == NULL) { printf("Failed to find the %s\n", trigger_name); return -1; } RingBufferDirectoryName = find_ring_subelement(BaseDirectoryName, "ring_buffer"); if (RingBufferDirectoryName == NULL) { printf("Failed to find ring buffer\n"); return -1; } if (write_sysfs_string_and_verify("trigger/current_trigger", BaseDirectoryName, (char *)trigger_name) < 0) { printf("Failed to write current_trigger file \n"); return -1; } /* Setup ring buffer parameters */ if (write_sysfs_int("length", RingBufferDirectoryName, RingLength) < 0) { printf("Failed to open the ring buffer length file \n"); return -1; } /* Enable the ring buffer */ if (write_sysfs_int("ring_enable", RingBufferDirectoryName, 1) < 0) { printf("Failed to open the ring buffer control file \n"); return -1; }; data = malloc(size_from_scanmode(NumVals, scan_ts)*RingLength); if (!data) { printf("Could not allocate space for usespace data store\n"); return -1; } /* Attempt to open non blocking the access dev */ fp = open(ring_access, O_RDONLY | O_NONBLOCK); if (fp == -1) { /*If it isn't there make the node */ printf("Failed to open %s\n", ring_access); return -1; } /* Attempt to open the event access dev (blocking this time) */ fp_ev = fopen(ring_event, "rb"); if (fp_ev == NULL) { printf("Failed to open %s\n", ring_event); return -1; } /* Wait for events 10 times */ for (j = 0; j < 10; j++) { read_size = fread(&dat, 1, sizeof(struct iio_event_data), fp_ev); switch (dat.id) { case IIO_EVENT_CODE_RING_100_FULL: toread = RingLength; break; case IIO_EVENT_CODE_RING_75_FULL: toread = RingLength*3/4; break; case IIO_EVENT_CODE_RING_50_FULL: toread = RingLength/2; break; default: printf("Unexpecteded event code\n"); continue; } read_size = read(fp, data, toread*size_from_scanmode(NumVals, scan_ts)); if (read_size == -EAGAIN) { printf("nothing available \n"); continue; } for (i = 0; i < read_size/size_from_scanmode(NumVals, scan_ts); i++) { for (k = 0; k < NumVals; k++) { __s16 val = *(__s16 *)(&data[i*size_from_scanmode(NumVals, scan_ts) + (k)*2]); printf("%05d ", val); } printf(" %lld\n", *(__s64 *)(&data[(i+1)*size_from_scanmode(NumVals, scan_ts) - sizeof(__s64)])); } } /* Stop the ring buffer */ if (write_sysfs_int("ring_enable", RingBufferDirectoryName, 0) < 0) { printf("Failed to open the ring buffer control file \n"); return -1; }; /* Disconnect from the trigger - writing something that doesn't exist.*/ write_sysfs_string_and_verify("trigger/current_trigger", BaseDirectoryName, "NULL"); free(BaseDirectoryName); free(TriggerDirectoryName); free(RingBufferDirectoryName); free(data); return 0; } drivers/staging/iio/Documentation/overview.txt 0 → 100644 +62 −0 Original line number Diff line number Diff line Overview of IIO The Industrial I/O subsytem is intended to provide support for devices that in some sense are analog to digital convertors (ADCs). As many actual devices combine some ADCs with digital to analog convertors (DACs) the intention is to add that functionality at a future date (hence the name). The aim is to fill the gap between the somewhat similar hwmon and input subsystems. Hwmon is very much directed at low sample rate sensors used in applications such as fan speed control and temperature measurement. Input is, as it's name suggests focused on input devices. In some cases there is considerable overlap between these and IIO. A typical device falling into this category would be connected via SPI or I2C. Functionality of IIO * Basic device registration and handling. This is very similar to hwmon with simple polled access to device channels via sysfs. * Event chrdevs. These are similar to input in that they provide a route to user space for hardware triggered events. Such events include threshold detectors, free-fall detectors and more complex action detection. They events themselves are currently very simple with merely an event code and a timestamp. Any data associated with the event must be accessed via polling. Note a given device may have one or more event channel. These events are turned on or off (if possible) via sysfs interfaces. * Hardware ring buffer support. Some recent sensors have included fifo / ring buffers on the sensor chip. These greatly reduce the load on the host CPU by buffering relatively large numbers of data samples based on an internal sampling clock. Examples include VTI SCA3000 series and Analog Device ADXL345 accelerometers. Each ring buffer typically has an event chrdev (similar to the more general ones above) to pass on events such as buffer 50% full and an access chrdev via which the raw data it self may be read back. * Trigger and software ring buffer support. In many data analysis applications it it useful to be able to capture data based on some external signal (trigger). These triggers might be a data ready signal, a gpio line connected to some external system or an on processor periodic interrupt. A single trigger many initialize data capture or reading from a number of sensors. These triggers are used in iio to fill software ring buffers acting in a very similar fashion to the hardware buffers described above. Other documentation: userspace.txt - overview of ring buffer reading from userspace device.txt - elemennts of a typical device driver. trigger.txt - elements of a typical trigger driver. ring.txt - additional elements required for ring buffer support drivers/staging/iio/Documentation/ring.txt 0 → 100644 +61 −0 Original line number Diff line number Diff line Ring buffer support within IIO This document is intended as a general overview of the functionality a ring buffer may supply and how it is specified within IIO. For more specific information on a given ring buffer implementation, see the comments in the source code. Note that the intention is to allow some drivers to specify ring buffers choice at probe or runtime, but for now the selection is hard coded within a given driver. A given ring buffer implementation typically embedded a struct iio_ring_buffer and it is a pointer to this that is provided to the IIO core. Access to the embedding structure is typically done via container_of functions. struct iio_ring_buffer contains 4 function pointers (preenable, postenable, predisable, postdisable). These are used to perform implementation specific steps on either side of the core changing it's current mode to indicate that the ring buffer is enabled or disabled (along with enabling triggering etc as appropriate). Also in struct iio_ring_buffer is a struct iio_ring_access_funcs. The function pointers within here are used to allow the core to handle as much ring buffer functionality as possible. Note almost all of these are optional. mark_in_use, unmark_in_use Basically indicate that not changes should be made to the ring buffer state that will effect the form of the data being captures (e.g. scan elements or length) store_to If possible, push data to ring buffer. read_last If possible get the most recent entry from the buffer (without removal). This provides polling like functionality whilst the ring buffering is in use without a separate read from the device. rip_lots The primary ring buffer reading function. Note that it may well not return as much data as requested. The deadoffset is used to indicate that some initial data in the data array is not guaranteed to be valid. mark_param_changed Used to indicate that something has changed. Used in conjunction with request_update If parameters have changed that require reinitialization or configuration of the ring buffer this will trigger it. get_bpd, set_bpd Get/set the number of bytes for a given reading (single element, not sample set) The value of bps (bytes per set) is created from a combination of this and the enabled scan elements. get_length / set_length Get/set the number of sample sets that may be held by the buffer. is_enabled Query if ring buffer is in use enable Start the ring buffer. Loading
drivers/staging/iio/Documentation/device.txt 0 → 100644 +49 −0 Original line number Diff line number Diff line IIO Device drivers This is not intended to provide a comprehensive guide to writing an IIO device driver. For further information see the drivers within the subsystem. The crucial structure for device drivers in iio is iio_dev. First allocate one using: struct iio_dev *indio_dev = iio_allocate_device(); The fill in the following. indio_dev->dev.parent the struct device associated with the underlying hardware. indio_dev->num_interrupt_lines number of event triggering hardware lines the device has. indio_dev->event_attrs attributes used to enable / disable hardware events - note the attributes are embedded in iio_event_attr structures with an associated iio_event_handler which may or may note be shared. If num_interrupt_lines = 0, then no need to fill this in. indio_dev->attrs general attributes such as polled access to device channels. indio_dev->dev_data private device specific data. indio_dev->driver_module typically set to THIS_MODULE. Used to specify ownership of some iio created resources. indio_dev->modes whether direct access and / or ring buffer access is supported. Once these are set up, a call to iio_device_register(indio_dev), will register the device with the iio core. Worth noting here is that, if a ring buffer is to be used, it can be allocated prior to registering the device with the iio-core, but must be registered afterwards (otherwise the whole parentage of devices gets confused) On remove iio_device_unregister(indio_dev) will remove the device from the core, and iio_free_device will clean up.
drivers/staging/iio/Documentation/iio_utils.h 0 → 100644 +159 −0 Original line number Diff line number Diff line /* IIO - useful set of util functionality * * 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. */ #define IIO_EVENT_CODE_RING_50_FULL 200 #define IIO_EVENT_CODE_RING_75_FULL 201 #define IIO_EVENT_CODE_RING_100_FULL 202 struct iio_event_data { int id; __s64 timestamp; }; inline char *find_ring_subelement(const char *directory, const char *subelement) { DIR *dp; const struct dirent *ent; int pos; char temp[100]; char *returnstring; dp = opendir(directory); if (dp == NULL) { printf("could not directory: %s\n", directory); return NULL; } while (ent = readdir(dp), ent != NULL) { if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) { if (strncmp(ent->d_name, subelement, strlen(subelement)) == 0) { int length = sprintf(temp, "%s%s%s", directory, ent->d_name, "/"); returnstring = malloc(length+1); strncpy(returnstring, temp, length+1); return returnstring; } } } return 0; } char *find_type_by_name(const char *name, const char *type) { const char *iio_dir = "/sys/class/iio/"; const struct dirent *ent; int cnt, pos, pos2; FILE *nameFile; DIR *dp; char thisname[100]; char temp[100]; char *returnstring = NULL; struct stat Stat; pos = sprintf(temp, "%s", iio_dir); dp = opendir(iio_dir); if (dp == NULL) { printf("No industrialio devices available"); return NULL; } while (ent = readdir(dp), ent != NULL) { cnt++; /*reject . and .. */ if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) { /*make sure it isn't a trigger!*/ if (strncmp(ent->d_name, type, strlen(type)) == 0) { /* build full path to new file */ pos2 = pos + sprintf(temp + pos, "%s/", ent->d_name); sprintf(temp + pos2, "name"); printf("search location %s\n", temp); nameFile = fopen(temp, "r"); if (!nameFile) { sprintf(temp + pos2, "modalias", ent->d_name); nameFile = fopen(temp, "r"); if (!nameFile) { printf("Failed to find a name for device\n"); return NULL; } } fscanf(nameFile, "%s", thisname); if (strcmp(name, thisname) == 0) { returnstring = malloc(strlen(temp) + 1); sprintf(temp + pos2, ""); strcpy(returnstring, temp); return returnstring; } fclose(nameFile); } } } } int write_sysfs_int(char *filename, char *basedir, int val) { int ret; FILE *sysfsfp; char temp[100]; sprintf(temp, "%s%s", basedir, filename); sysfsfp = fopen(temp, "w"); if (sysfsfp == NULL) return -1; fprintf(sysfsfp, "%d", val); fclose(sysfsfp); return 0; } /** * write_sysfs_string_and_verify() - string write, readback and verify * @filename: name of file to write to * @basedir: the sysfs directory in which the file is to be found * @val: the string to write **/ int write_sysfs_string_and_verify(char *filename, char *basedir, char *val) { int ret; FILE *sysfsfp; char temp[100]; sprintf(temp, "%s%s", basedir, filename); sysfsfp = fopen(temp, "w"); if (sysfsfp == NULL) return -1; fprintf(sysfsfp, "%s", val); fclose(sysfsfp); sysfsfp = fopen(temp, "r"); if (sysfsfp == NULL) return -1; fscanf(sysfsfp, "%s", temp); if (strcmp(temp, val) != 0) { printf("Possible failure in string write %s to %s%s \n", val, basedir, filename); return -1; } return 0; } int read_sysfs_posint(char *filename, char *basedir) { int ret; FILE *sysfsfp; char temp[100]; sprintf(temp, "%s%s", basedir, filename); sysfsfp = fopen(temp, "r"); if (sysfsfp == NULL) return -1; fscanf(sysfsfp, "%d\n", &ret); fclose(sysfsfp); return ret; }
drivers/staging/iio/Documentation/lis3l02dqbuffersimple.c 0 → 100644 +171 −0 Original line number Diff line number Diff line /* Industrialio test ring buffer with a lis3l02dq acceleromter * * 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. * * Assumes suitable udev rules are used to create the dev nodes as named here. */ #include <dirent.h> #include <fcntl.h> #include <stdio.h> #include <errno.h> #include <stdint.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/dir.h> #include <linux/types.h> #include <dirent.h> #include "iio_util.h" static const char *ring_access = "/dev/iio/lis3l02dq_ring_access"; static const char *ring_event = "/dev/iio/lis3l02dq_ring_event"; static const char *device_name = "lis3l02dq"; static const char *trigger_name = "lis3l02dq-dev0"; static int NumVals = 3; static int scan_ts = 1; static int RingLength = 128; /* * Could get this from ring bps, but only after starting the ring * which is a bit late for it to be useful */ int size_from_scanmode(int numVals, int timestamp) { if (numVals && timestamp) return 16; else if (timestamp) return 8; else return numVals*2; } int main(int argc, char **argv) { int i, j, k, toread; FILE *fp_ev; int fp; char *data; size_t read_size; struct iio_event_data dat; char *BaseDirectoryName, *TriggerDirectoryName, *RingBufferDirectoryName; BaseDirectoryName = find_type_by_name(device_name, "device"); if (BaseDirectoryName == NULL) { printf("Failed to find the %s \n", device_name); return -1; } TriggerDirectoryName = find_type_by_name(trigger_name, "trigger"); if (TriggerDirectoryName == NULL) { printf("Failed to find the %s\n", trigger_name); return -1; } RingBufferDirectoryName = find_ring_subelement(BaseDirectoryName, "ring_buffer"); if (RingBufferDirectoryName == NULL) { printf("Failed to find ring buffer\n"); return -1; } if (write_sysfs_string_and_verify("trigger/current_trigger", BaseDirectoryName, (char *)trigger_name) < 0) { printf("Failed to write current_trigger file \n"); return -1; } /* Setup ring buffer parameters */ if (write_sysfs_int("length", RingBufferDirectoryName, RingLength) < 0) { printf("Failed to open the ring buffer length file \n"); return -1; } /* Enable the ring buffer */ if (write_sysfs_int("ring_enable", RingBufferDirectoryName, 1) < 0) { printf("Failed to open the ring buffer control file \n"); return -1; }; data = malloc(size_from_scanmode(NumVals, scan_ts)*RingLength); if (!data) { printf("Could not allocate space for usespace data store\n"); return -1; } /* Attempt to open non blocking the access dev */ fp = open(ring_access, O_RDONLY | O_NONBLOCK); if (fp == -1) { /*If it isn't there make the node */ printf("Failed to open %s\n", ring_access); return -1; } /* Attempt to open the event access dev (blocking this time) */ fp_ev = fopen(ring_event, "rb"); if (fp_ev == NULL) { printf("Failed to open %s\n", ring_event); return -1; } /* Wait for events 10 times */ for (j = 0; j < 10; j++) { read_size = fread(&dat, 1, sizeof(struct iio_event_data), fp_ev); switch (dat.id) { case IIO_EVENT_CODE_RING_100_FULL: toread = RingLength; break; case IIO_EVENT_CODE_RING_75_FULL: toread = RingLength*3/4; break; case IIO_EVENT_CODE_RING_50_FULL: toread = RingLength/2; break; default: printf("Unexpecteded event code\n"); continue; } read_size = read(fp, data, toread*size_from_scanmode(NumVals, scan_ts)); if (read_size == -EAGAIN) { printf("nothing available \n"); continue; } for (i = 0; i < read_size/size_from_scanmode(NumVals, scan_ts); i++) { for (k = 0; k < NumVals; k++) { __s16 val = *(__s16 *)(&data[i*size_from_scanmode(NumVals, scan_ts) + (k)*2]); printf("%05d ", val); } printf(" %lld\n", *(__s64 *)(&data[(i+1)*size_from_scanmode(NumVals, scan_ts) - sizeof(__s64)])); } } /* Stop the ring buffer */ if (write_sysfs_int("ring_enable", RingBufferDirectoryName, 0) < 0) { printf("Failed to open the ring buffer control file \n"); return -1; }; /* Disconnect from the trigger - writing something that doesn't exist.*/ write_sysfs_string_and_verify("trigger/current_trigger", BaseDirectoryName, "NULL"); free(BaseDirectoryName); free(TriggerDirectoryName); free(RingBufferDirectoryName); free(data); return 0; }
drivers/staging/iio/Documentation/overview.txt 0 → 100644 +62 −0 Original line number Diff line number Diff line Overview of IIO The Industrial I/O subsytem is intended to provide support for devices that in some sense are analog to digital convertors (ADCs). As many actual devices combine some ADCs with digital to analog convertors (DACs) the intention is to add that functionality at a future date (hence the name). The aim is to fill the gap between the somewhat similar hwmon and input subsystems. Hwmon is very much directed at low sample rate sensors used in applications such as fan speed control and temperature measurement. Input is, as it's name suggests focused on input devices. In some cases there is considerable overlap between these and IIO. A typical device falling into this category would be connected via SPI or I2C. Functionality of IIO * Basic device registration and handling. This is very similar to hwmon with simple polled access to device channels via sysfs. * Event chrdevs. These are similar to input in that they provide a route to user space for hardware triggered events. Such events include threshold detectors, free-fall detectors and more complex action detection. They events themselves are currently very simple with merely an event code and a timestamp. Any data associated with the event must be accessed via polling. Note a given device may have one or more event channel. These events are turned on or off (if possible) via sysfs interfaces. * Hardware ring buffer support. Some recent sensors have included fifo / ring buffers on the sensor chip. These greatly reduce the load on the host CPU by buffering relatively large numbers of data samples based on an internal sampling clock. Examples include VTI SCA3000 series and Analog Device ADXL345 accelerometers. Each ring buffer typically has an event chrdev (similar to the more general ones above) to pass on events such as buffer 50% full and an access chrdev via which the raw data it self may be read back. * Trigger and software ring buffer support. In many data analysis applications it it useful to be able to capture data based on some external signal (trigger). These triggers might be a data ready signal, a gpio line connected to some external system or an on processor periodic interrupt. A single trigger many initialize data capture or reading from a number of sensors. These triggers are used in iio to fill software ring buffers acting in a very similar fashion to the hardware buffers described above. Other documentation: userspace.txt - overview of ring buffer reading from userspace device.txt - elemennts of a typical device driver. trigger.txt - elements of a typical trigger driver. ring.txt - additional elements required for ring buffer support
drivers/staging/iio/Documentation/ring.txt 0 → 100644 +61 −0 Original line number Diff line number Diff line Ring buffer support within IIO This document is intended as a general overview of the functionality a ring buffer may supply and how it is specified within IIO. For more specific information on a given ring buffer implementation, see the comments in the source code. Note that the intention is to allow some drivers to specify ring buffers choice at probe or runtime, but for now the selection is hard coded within a given driver. A given ring buffer implementation typically embedded a struct iio_ring_buffer and it is a pointer to this that is provided to the IIO core. Access to the embedding structure is typically done via container_of functions. struct iio_ring_buffer contains 4 function pointers (preenable, postenable, predisable, postdisable). These are used to perform implementation specific steps on either side of the core changing it's current mode to indicate that the ring buffer is enabled or disabled (along with enabling triggering etc as appropriate). Also in struct iio_ring_buffer is a struct iio_ring_access_funcs. The function pointers within here are used to allow the core to handle as much ring buffer functionality as possible. Note almost all of these are optional. mark_in_use, unmark_in_use Basically indicate that not changes should be made to the ring buffer state that will effect the form of the data being captures (e.g. scan elements or length) store_to If possible, push data to ring buffer. read_last If possible get the most recent entry from the buffer (without removal). This provides polling like functionality whilst the ring buffering is in use without a separate read from the device. rip_lots The primary ring buffer reading function. Note that it may well not return as much data as requested. The deadoffset is used to indicate that some initial data in the data array is not guaranteed to be valid. mark_param_changed Used to indicate that something has changed. Used in conjunction with request_update If parameters have changed that require reinitialization or configuration of the ring buffer this will trigger it. get_bpd, set_bpd Get/set the number of bytes for a given reading (single element, not sample set) The value of bps (bytes per set) is created from a combination of this and the enabled scan elements. get_length / set_length Get/set the number of sample sets that may be held by the buffer. is_enabled Query if ring buffer is in use enable Start the ring buffer.