Sure.. Below is the kernel module, header file, and user process. (3 files
total). Note that I am doing some EVIL things with shared memory (like
wasting a LOT of it) but this was for testing porpoises only. Note that
this stuff doesn't much make use of rtlinux, but it IS a kernel module
talking to a user process, using the shared memory mechanism. It is only
to show how to access comedi from kernel space.. and i just use it as test
code. Again I apologize for the inefficiency herein. Also I prefer a sort
of modest indentation (2 spaces). That drives most people nuts, so that's
why I do it. I think 8 space tabs are RIDICULOUS, despite what certain
chubby developers from finland now working for transleta might tell you.
-Calin
--------------BEGIN kct.c (compile as a kernel module with the usual bells
and whistles that implies)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/comedilib.h>
#include <mbuff.h> /* from rtlinux */
#include "kct.h"
struct probe_info *probed_info;
int aref = AREF_GROUND; /* more on this later */
comedi_krange range;
int range_index = 3;
lsampl_t maxdata, data;
double volts;
int probeall(struct minor_info *); // returns 0 on success, otherwise
returns an error code
int init_module(void) {
int ret;
if ( !(probed_info = mbuff_alloc(SHARED_MBUFFER_NAME,
SHARED_MBUFFER_SIZE)) ) {
printk(KERN_ERR "No memory for shared buffer, aborting!\n");
return -ENOMEM;
}
ret = probeall(probed_info->devices);
if (ret < 0) {
printk(KERN_ERR "Probe found an error, aborting module!\n");
return ret;
}
/* else probe at least ran ok,
so grab the number of devices it said it found */
probed_info->num_devices_found = ret;
if (!probed_info->num_devices_found) {
printk(KERN_ERR "No devices found, aborting module!\n");
return -ENODEV;
}
return 0;
}
void cleanup_module (void) {
int i;
if (probed_info) {
for (i = 0; i < probed_info->num_devices_found; i++) {
comedi_close(i);
}
mbuff_free(SHARED_MBUFFER_NAME, probed_info);
}
}
/* returns the number of devices successfully probed, or an errno
value on error
Pass in a (preferabbly mbuff_alloc'd) minor_info array
of size COMEDI_NDEVICES
NB: This function modifies the probed_info
*/
int probeall(struct minor_info *probed_info) {
unsigned int num_devs_found = 0;
/* try to open devices.. if one fails we assume it doesn't exist */
for (; num_devs_found < MAX_CHANNELS; num_devs_found++) {
int i, tmp, minor = comedi_open(num_devs_found);
char *driver_name, *board_name;
if (minor < 0) {
break; /* assume we already hit the first invalid device, so abort
(this assumption might be slightly incorrect, as we
also get an error if this device is attached) */
}
driver_name = comedi_get_driver_name(minor);
board_name = comedi_get_board_name(minor);
if (driver_name && board_name) {
memcpy (probed_info[minor].board_name, board_name, COMEDI_NAMELEN);
memcpy (probed_info[minor].driver_name, driver_name,
COMEDI_NAMELEN);
printk (KERN_INFO "Found board at device minor number %d named `%s'
(driver: `%s')\n", minor, probed_info[minor].board_name,
probed_info[minor].driver_name);
} else {
printk (KERN_ERR "Unexpected error querying board and driver names
on comedi device minor numbered %d!\n", minor);
return -ENOMSG;
}
tmp = comedi_get_n_subdevices(minor);
if (tmp < 0) {
printk(KERN_ERR "Unexpected error while querying minor %d(%s) on the
number of subdevices it contains!\n", minor,
probed_info[minor].board_name);
return tmp;
}
probed_info[minor].n_subdevices = tmp;
/* now probe this found device to death (note the super-nesting here!)
*/
for (i = 0; i < probed_info[minor].n_subdevices; i++) {
int j;
tmp = comedi_get_subdevice_type(minor, i);
if (tmp < 0) {
printk (KERN_ERR "For some reason, subdevice %d on minor device
number %d(%s) returned an error when querying the subdevice's type!\n", i,
minor, probed_info[minor].board_name);
return tmp;
}
probed_info[minor].subdevices[i].subdev_type = tmp;
tmp = comedi_get_n_channels(minor,i);
if (tmp < 0) {
printk (KERN_ERR "Failed to query the number of channels on
subdevice %d, minor device %d(%s)!\n", i, minor,
probed_info[minor].board_name);
return tmp;
}
probed_info[minor].subdevices[i].n_channels = tmp;
for (j = 0; j < probed_info[minor].subdevices[i].n_channels; j++) {
int k;
lsampl_t tmp_lsampl = comedi_get_maxdata(minor, i, j);
if (tmp_lsampl < 0) {
printk (KERN_ERR "Failed to get maxdata on channel %d, subdev
%d, minor device number %d(%s)!\n", j, i, minor,
probed_info[minor].board_name);
return tmp_lsampl;
}
probed_info[minor].subdevices[i].channels[j].maxdata = tmp_lsampl;
tmp = comedi_get_n_ranges(minor, i, j);
if (tmp < 0) {
printk (KERN_ERR "Failed to query n_ranges for channel %d on
subdev %d comedi device number %d(%s)!\n", j, i, minor,
probed_info[minor].board_name);
return tmp;
}
probed_info[minor].subdevices[i].channels[j].n_ranges = tmp;
probed_info[minor].subdevices[i].channels[j].current_range_setting
= 0;
for (k = 0; k <
probed_info[minor].subdevices[i].channels[j].n_ranges;
k++) {
comedi_krange tmp_range;
tmp = comedi_get_krange ( minor, i, j, k, &tmp_range );
if ( tmp < 0) {
printk (KERN_ERR "Error returned from comedi_get_krange on
range %d, channel %d, subdev %d, minor %d(%s)!\n", k, j, i, minor,
probed_info[minor].board_name);
return tmp;
}
/* Everything's ok--now convert stupid krange_struct to
range_info */
probed_info[minor].subdevices[i].channels[j].ranges[k].min =
tmp_range.min * 1e-6;
probed_info[minor].subdevices[i].channels[j].ranges[k].max =
tmp_range.max * 1e-6;
probed_info[minor].subdevices[i].channels[j].ranges[k].unit =
tmp_range.flags;
}
}
}
}
return num_devs_found;
}
-------------- BEGIN kct.h (header file shared by user and kenerl process)
#ifndef _KCT_H
#define _KCT_H
/* this is for COMEDI_NDEVICES */
#ifdef __KERNEL__
# include <linux/comedi.h>
#else
# include <comedi.h>
#endif
#define MAX_SUBDEVICES 16
#define MAX_CHANNELS 64
#define MAX_RANGES 256
struct range_info {
double max;
double min;
unsigned int unit;
};
struct chan_info {
lsampl_t maxdata;
unsigned int n_ranges;
unsigned int current_range_setting;
struct range_info ranges[MAX_RANGES];
};
struct subdev_info {
int subdev_type;
int n_channels;
struct chan_info channels[MAX_CHANNELS];
};
struct minor_info {
char driver_name[COMEDI_NAMELEN];
char board_name[COMEDI_NAMELEN];
int n_subdevices;
struct subdev_info subdevices[MAX_SUBDEVICES];
};
struct probe_info {
int num_devices_found;
struct minor_info devices[COMEDI_NDEVICES];
};
#define SHARED_MBUFFER_NAME "KCT Memory Buf"
#define SHARED_MBUFFER_SIZE sizeof(struct probe_info)
#endif
-------------- BEGIN kctu.c (user process that grabs some info from the
kernel process [kct] and displays it on the screen)
/*
The user-space program that uses shared memory to grab data from
the kernel module 'kct'
*/
#include <stdio.h>
#include <mbuff.h>
#include <comedi.h>
#include "kct.h"
static const char *get_subdev_type_name(unsigned int subdev_type);
static const char *get_range_string(unsigned int unit);
int
main (void) {
int i;
struct probe_info *info = (struct probe_info
*)mbuff_attach(SHARED_MBUFFER_NAME, SHARED_MBUFFER_SIZE);
if (!info) {
printf("Cannot attach to mbuff called %s\n", SHARED_MBUFFER_NAME);
return 1;
} else {
printf("(Memory buffer is of size %d)\n", SHARED_MBUFFER_SIZE);
}
printf ("Found %d boards\n", info->num_devices_found);
if (info->num_devices_found == 0) {
printf("It's possible that there are actually some boards but that the
kernel module is not loaded!\n");
}
for (i = 0; i < info->num_devices_found; i++) {
int j;
struct minor_info *device = info->devices+i;
printf("Device minor number %d has name %s with %d subdevices\n", i,
device->board_name, device->n_subdevices);
for (j = 0; j < device->n_subdevices; j++) {
struct subdev_info *subdevice = device->subdevices+j;
int k;
printf(" Device number %d, subdevice %d is of type %s, with %d
channels\n", i, j, get_subdev_type_name(subdevice->subdev_type),
subdevice->n_channels);
for (k = 0; k < subdevice->n_channels; k++) {
int l;
struct chan_info *channel = subdevice->channels+k;
printf(" Channel %d has %d ranges with maxdata %d\n", k,
channel->n_ranges, channel->maxdata);
for (l = 0; l < channel->n_ranges; l++) {
struct range_info *range = channel->ranges+l;
printf(" Range %d goes from %g to %g with units %s\n", l,
range->min, range->max, get_range_string(range->unit));
}
}
}
}
mbuff_detach("Test", info);
return 0;
}
static const char *get_subdev_type_name(unsigned int subdev_type) {
switch (subdev_type) {
case COMEDI_SUBD_UNUSED: return "<unused>";
case COMEDI_SUBD_AI: return "<analog input>";
case COMEDI_SUBD_AO: return "<analog output>";
case COMEDI_SUBD_DI: return "<digital input>";
case COMEDI_SUBD_DO: return "<digital output>";
case COMEDI_SUBD_DIO: return "<digital input/output>";
case COMEDI_SUBD_COUNTER: return "<counter>";
case COMEDI_SUBD_TIMER: return "<timer>";
case COMEDI_SUBD_MEMORY: return "<memory, EEPROM, DPRAM>";
case COMEDI_SUBD_CALIB: return "<calibration DACs>";
case COMEDI_SUBD_PROC: return "<processor, DSP>";
default: return "--->illegal device type<---";
}
}
static const char *get_range_string(unsigned int unit) {
switch (unit) {
case UNIT_volt: return "[Volts]";
case UNIT_mA: return "[milliAmps?]";
case UNIT_none: return "[no unit]";
default: return "--->illegal unit type<---";
}
}
--------------
> sorry ,I'm a newbie,I never had comedi worked with rtlinux,any version.
> can you send me your code example that comedi worked with rtlinux?
>
> thanks!
> at80401
> --- Calin Culianu <[EMAIL PROTECTED]> wrote:
> >
> > I am struggling to get the latest comedi (comedi 0.7.60, comedilib
> > 0.7.16) working with RTLinux 3.1 on kernel 2.4.4.
> >
> > I am having trouble.
> >
> > Basically, the comedi header files seem to be redefining (or calling some
> > other .h's that redefine) some of the posix thread types. Furthermore,
> > the redefined types are different than the rtl pthread types.
> >
> > Has anyone on this mailing list successfully gotten the lastest comedi to
> > work with the latest rtl? If so, what am I doing wrong and/or what did
> > you do to solve this problem?
> >
> > -Calin
> >
> >
> > -- [rtl] ---
> > To unsubscribe:
> > echo "unsubscribe rtl" | mail [EMAIL PROTECTED] OR
> > echo "unsubscribe rtl <Your_email>" | mail [EMAIL PROTECTED]
> > --
> > For more information on Real-Time Linux see:
> > http://www.rtlinux.org/
> >
>
>
> __________________________________________________
> Do You Yahoo!?
> Get email alerts & NEW webcam video instant messaging with Yahoo! Messenger
> http://im.yahoo.com
>
> -- [rtl] ---
> To unsubscribe:
> echo "unsubscribe rtl" | mail [EMAIL PROTECTED] OR
> echo "unsubscribe rtl <Your_email>" | mail [EMAIL PROTECTED]
> --
> For more information on Real-Time Linux see:
> http://www.rtlinux.org/
>
>
-- [rtl] ---
To unsubscribe:
echo "unsubscribe rtl" | mail [EMAIL PROTECTED] OR
echo "unsubscribe rtl <Your_email>" | mail [EMAIL PROTECTED]
--
For more information on Real-Time Linux see:
http://www.rtlinux.org/