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/

Reply via email to