-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jonathan Cameron
authored and
Greg Kroah-Hartman
committed
Sep 15, 2009
1 parent
20b79f1
commit 272c42a
Showing
8 changed files
with
601 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 930bae8667c100d727360c0fa0df0378af9097ea | ||
refs/heads/master: c57f1ba7326100fd90c35259a588a8484bf569b4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
/* 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; | ||
} |
171 changes: 171 additions & 0 deletions
171
trunk/drivers/staging/iio/Documentation/lis3l02dqbuffersimple.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
/* 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; | ||
} |
Oops, something went wrong.