Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/comedi/drivers/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 19 kB image not shown  

Quelle  jr3_pci.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0+
/*
 * comedi/drivers/jr3_pci.c
 * hardware driver for JR3/PCI force sensor board
 *
 * COMEDI - Linux Control and Measurement Device Interface
 * Copyright (C) 2007 Anders Blomdell <anders.blomdell@control.lth.se>
 */

/*
 * Driver: jr3_pci
 * Description: JR3/PCI force sensor board
 * Author: Anders Blomdell <anders.blomdell@control.lth.se>
 * Updated: Thu, 01 Nov 2012 17:34:55 +0000
 * Status: works
 * Devices: [JR3] PCI force sensor board (jr3_pci)
 *
 * Configuration options:
 *   None
 *
 * Manual configuration of comedi devices is not supported by this
 * driver; supported PCI devices are configured as comedi devices
 * automatically.
 *
 * The DSP on the board requires initialization code, which can be
 * loaded by placing it in /lib/firmware/comedi.  The initialization
 * code should be somewhere on the media you got with your card.  One
 * version is available from https://www.comedi.org in the
 * comedi_nonfree_firmware tarball.  The file is called "jr3pci.idm".
 */


#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/comedi/comedi_pci.h>

#include "jr3_pci.h"

#define PCI_VENDOR_ID_JR3 0x1762

enum jr3_pci_boardid {
 BOARD_JR3_1,
 BOARD_JR3_2,
 BOARD_JR3_3,
 BOARD_JR3_4,
};

struct jr3_pci_board {
 const char *name;
 int n_subdevs;
};

static const struct jr3_pci_board jr3_pci_boards[] = {
 [BOARD_JR3_1] = {
  .name  = "jr3_pci_1",
  .n_subdevs = 1,
 },
 [BOARD_JR3_2] = {
  .name  = "jr3_pci_2",
  .n_subdevs = 2,
 },
 [BOARD_JR3_3] = {
  .name  = "jr3_pci_3",
  .n_subdevs = 3,
 },
 [BOARD_JR3_4] = {
  .name  = "jr3_pci_4",
  .n_subdevs = 4,
 },
};

struct jr3_pci_transform {
 struct {
  u16 link_type;
  s16 link_amount;
 } link[8];
};

struct jr3_pci_poll_delay {
 int min;
 int max;
};

struct jr3_pci_dev_private {
 struct timer_list timer;
 struct comedi_device *dev;
};

union jr3_pci_single_range {
 struct comedi_lrange l;
 char _reserved[offsetof(struct comedi_lrange, range[1])];
};

enum jr3_pci_poll_state {
 state_jr3_poll,
 state_jr3_init_wait_for_offset,
 state_jr3_init_transform_complete,
 state_jr3_init_set_full_scale_complete,
 state_jr3_init_use_offset_complete,
 state_jr3_done
};

struct jr3_pci_subdev_private {
 struct jr3_sensor __iomem *sensor;
 unsigned long next_time_min;
 enum jr3_pci_poll_state state;
 int serial_no;
 int model_no;
 union jr3_pci_single_range range[9];
 const struct comedi_lrange *range_table_list[8 * 7 + 2];
 unsigned int maxdata_list[8 * 7 + 2];
 u16 errors;
 int retries;
};

static struct jr3_pci_poll_delay poll_delay_min_max(int min, int max)
{
 struct jr3_pci_poll_delay result;

 result.min = min;
 result.max = max;
 return result;
}

static int is_complete(struct jr3_sensor __iomem *sensor)
{
 return get_s16(&sensor->command_word0) == 0;
}

static void set_transforms(struct jr3_sensor __iomem *sensor,
      const struct jr3_pci_transform *transf, short num)
{
 int i;

 num &= 0x000f;  /* Make sure that 0 <= num <= 15 */
 for (i = 0; i < 8; i++) {
  set_u16(&sensor->transforms[num].link[i].link_type,
   transf->link[i].link_type);
  udelay(1);
  set_s16(&sensor->transforms[num].link[i].link_amount,
   transf->link[i].link_amount);
  udelay(1);
  if (transf->link[i].link_type == end_x_form)
   break;
 }
}

static void use_transform(struct jr3_sensor __iomem *sensor,
     short transf_num)
{
 set_s16(&sensor->command_word0, 0x0500 + (transf_num & 0x000f));
}

static void use_offset(struct jr3_sensor __iomem *sensor, short offset_num)
{
 set_s16(&sensor->command_word0, 0x0600 + (offset_num & 0x000f));
}

static void set_offset(struct jr3_sensor __iomem *sensor)
{
 set_s16(&sensor->command_word0, 0x0700);
}

struct six_axis_t {
 s16 fx;
 s16 fy;
 s16 fz;
 s16 mx;
 s16 my;
 s16 mz;
};

static void set_full_scales(struct jr3_sensor __iomem *sensor,
       struct six_axis_t full_scale)
{
 set_s16(&sensor->full_scale.fx, full_scale.fx);
 set_s16(&sensor->full_scale.fy, full_scale.fy);
 set_s16(&sensor->full_scale.fz, full_scale.fz);
 set_s16(&sensor->full_scale.mx, full_scale.mx);
 set_s16(&sensor->full_scale.my, full_scale.my);
 set_s16(&sensor->full_scale.mz, full_scale.mz);
 set_s16(&sensor->command_word0, 0x0a00);
}

static struct six_axis_t get_max_full_scales(struct jr3_sensor __iomem *sensor)
{
 struct six_axis_t result;

 result.fx = get_s16(&sensor->max_full_scale.fx);
 result.fy = get_s16(&sensor->max_full_scale.fy);
 result.fz = get_s16(&sensor->max_full_scale.fz);
 result.mx = get_s16(&sensor->max_full_scale.mx);
 result.my = get_s16(&sensor->max_full_scale.my);
 result.mz = get_s16(&sensor->max_full_scale.mz);
 return result;
}

static unsigned int jr3_pci_ai_read_chan(struct comedi_device *dev,
      struct comedi_subdevice *s,
      unsigned int chan)
{
 struct jr3_pci_subdev_private *spriv = s->private;
 unsigned int val = 0;

 if (spriv->state != state_jr3_done)
  return 0;

 if (chan < 56) {
  unsigned int axis = chan % 8;
  unsigned int filter = chan / 8;

  switch (axis) {
  case 0:
   val = get_s16(&spriv->sensor->filter[filter].fx);
   break;
  case 1:
   val = get_s16(&spriv->sensor->filter[filter].fy);
   break;
  case 2:
   val = get_s16(&spriv->sensor->filter[filter].fz);
   break;
  case 3:
   val = get_s16(&spriv->sensor->filter[filter].mx);
   break;
  case 4:
   val = get_s16(&spriv->sensor->filter[filter].my);
   break;
  case 5:
   val = get_s16(&spriv->sensor->filter[filter].mz);
   break;
  case 6:
   val = get_s16(&spriv->sensor->filter[filter].v1);
   break;
  case 7:
   val = get_s16(&spriv->sensor->filter[filter].v2);
   break;
  }
  val += 0x4000;
 } else if (chan == 56) {
  val = get_u16(&spriv->sensor->model_no);
 } else if (chan == 57) {
  val = get_u16(&spriv->sensor->serial_no);
 }

 return val;
}

static int jr3_pci_ai_insn_read(struct comedi_device *dev,
    struct comedi_subdevice *s,
    struct comedi_insn *insn,
    unsigned int *data)
{
 struct jr3_pci_subdev_private *spriv = s->private;
 unsigned int chan = CR_CHAN(insn->chanspec);
 u16 errors;
 int i;

 errors = get_u16(&spriv->sensor->errors);
 if (spriv->state != state_jr3_done ||
     (errors & (watch_dog | watch_dog2 | sensor_change))) {
  /* No sensor or sensor changed */
  if (spriv->state == state_jr3_done) {
   /* Restart polling */
   spriv->state = state_jr3_poll;
  }
  return -EAGAIN;
 }

 for (i = 0; i < insn->n; i++)
  data[i] = jr3_pci_ai_read_chan(dev, s, chan);

 return insn->n;
}

static int jr3_pci_open(struct comedi_device *dev)
{
 struct jr3_pci_subdev_private *spriv;
 struct comedi_subdevice *s;
 int i;

 for (i = 0; i < dev->n_subdevices; i++) {
  s = &dev->subdevices[i];
  spriv = s->private;
  dev_dbg(dev->class_dev, "serial[%d]: %d\n", s->index,
   spriv->serial_no);
 }
 return 0;
}

static int read_idm_word(const u8 *data, size_t size, int *pos,
    unsigned int *val)
{
 int result = 0;
 int value;

 if (pos && val) {
  /* Skip over non hex */
  for (; *pos < size && !isxdigit(data[*pos]); (*pos)++)
   ;
  /* Collect value */
  *val = 0;
  for (; *pos < size; (*pos)++) {
   value = hex_to_bin(data[*pos]);
   if (value >= 0) {
    result = 1;
    *val = (*val << 4) + value;
   } else {
    break;
   }
  }
 }
 return result;
}

static int jr3_check_firmware(struct comedi_device *dev,
         const u8 *data, size_t size)
{
 int more = 1;
 int pos = 0;

 /*
 * IDM file format is:
 *   { count, address, data <count> } *
 *   ffff
 */

 while (more) {
  unsigned int count = 0;
  unsigned int addr = 0;

  more = more && read_idm_word(data, size, &pos, &count);
  if (more && count == 0xffff)
   return 0;

  more = more && read_idm_word(data, size, &pos, &addr);
  while (more && count > 0) {
   unsigned int dummy = 0;

   more = more && read_idm_word(data, size, &pos, &dummy);
   count--;
  }
 }

 return -ENODATA;
}

static void jr3_write_firmware(struct comedi_device *dev,
          int subdev, const u8 *data, size_t size)
{
 struct jr3_block __iomem *block = dev->mmio;
 u32 __iomem *lo;
 u32 __iomem *hi;
 int more = 1;
 int pos = 0;

 while (more) {
  unsigned int count = 0;
  unsigned int addr = 0;

  more = more && read_idm_word(data, size, &pos, &count);
  if (more && count == 0xffff)
   return;

  more = more && read_idm_word(data, size, &pos, &addr);

  dev_dbg(dev->class_dev, "Loading#%d %4.4x bytes at %4.4x\n",
   subdev, count, addr);

  while (more && count > 0) {
   if (addr & 0x4000) {
    /* 16 bit data, never seen in real life!! */
    unsigned int data1 = 0;

    more = more &&
           read_idm_word(data, size, &pos, &data1);
    count--;
    /* jr3[addr + 0x20000 * pnum] = data1; */
   } else {
    /* Download 24 bit program */
    unsigned int data1 = 0;
    unsigned int data2 = 0;

    lo = &block[subdev].program_lo[addr];
    hi = &block[subdev].program_hi[addr];

    more = more &&
           read_idm_word(data, size, &pos, &data1);
    more = more &&
           read_idm_word(data, size, &pos, &data2);
    count -= 2;
    if (more) {
     set_u16(lo, data1);
     udelay(1);
     set_u16(hi, data2);
     udelay(1);
    }
   }
   addr++;
  }
 }
}

static int jr3_download_firmware(struct comedi_device *dev,
     const u8 *data, size_t size,
     unsigned long context)
{
 int subdev;
 int ret;

 /* verify IDM file format */
 ret = jr3_check_firmware(dev, data, size);
 if (ret)
  return ret;

 /* write firmware to each subdevice */
 for (subdev = 0; subdev < dev->n_subdevices; subdev++)
  jr3_write_firmware(dev, subdev, data, size);

 return 0;
}

static struct jr3_pci_poll_delay
jr3_pci_poll_subdevice(struct comedi_subdevice *s)
{
 struct jr3_pci_subdev_private *spriv = s->private;
 struct jr3_pci_poll_delay result = poll_delay_min_max(1000, 2000);
 struct jr3_sensor __iomem *sensor;
 u16 model_no;
 u16 serial_no;
 int errors;
 int i;

 sensor = spriv->sensor;
 errors = get_u16(&sensor->errors);

 if (errors != spriv->errors)
  spriv->errors = errors;

 /* Sensor communication lost? force poll mode */
 if (errors & (watch_dog | watch_dog2 | sensor_change))
  spriv->state = state_jr3_poll;

 switch (spriv->state) {
 case state_jr3_poll:
  model_no = get_u16(&sensor->model_no);
  serial_no = get_u16(&sensor->serial_no);

  if ((errors & (watch_dog | watch_dog2)) ||
      model_no == 0 || serial_no == 0) {
   /*
 * Still no sensor, keep on polling.
 * Since it takes up to 10 seconds for offsets to
 * stabilize, polling each second should suffice.
 */

  } else {
   spriv->retries = 0;
   spriv->state = state_jr3_init_wait_for_offset;
  }
  break;
 case state_jr3_init_wait_for_offset:
  spriv->retries++;
  if (spriv->retries < 10) {
   /*
 * Wait for offeset to stabilize
 * (< 10 s according to manual)
 */

  } else {
   struct jr3_pci_transform transf;

   spriv->model_no = get_u16(&sensor->model_no);
   spriv->serial_no = get_u16(&sensor->serial_no);

   /* Transformation all zeros */
   for (i = 0; i < ARRAY_SIZE(transf.link); i++) {
    transf.link[i].link_type = (enum link_types)0;
    transf.link[i].link_amount = 0;
   }

   set_transforms(sensor, &transf, 0);
   use_transform(sensor, 0);
   spriv->state = state_jr3_init_transform_complete;
   /* Allow 20 ms for completion */
   result = poll_delay_min_max(20, 100);
  }
  break;
 case state_jr3_init_transform_complete:
  if (!is_complete(sensor)) {
   result = poll_delay_min_max(20, 100);
  } else {
   /* Set full scale */
   struct six_axis_t max_full_scale;

   max_full_scale = get_max_full_scales(sensor);
   set_full_scales(sensor, max_full_scale);

   spriv->state = state_jr3_init_set_full_scale_complete;
   /* Allow 20 ms for completion */
   result = poll_delay_min_max(20, 100);
  }
  break;
 case state_jr3_init_set_full_scale_complete:
  if (!is_complete(sensor)) {
   result = poll_delay_min_max(20, 100);
  } else {
   struct force_array __iomem *fs = &sensor->full_scale;
   union jr3_pci_single_range *r = spriv->range;

   /* Use ranges in kN or we will overflow around 2000N! */
   r[0].l.range[0].min = -get_s16(&fs->fx) * 1000;
   r[0].l.range[0].max = get_s16(&fs->fx) * 1000;
   r[1].l.range[0].min = -get_s16(&fs->fy) * 1000;
   r[1].l.range[0].max = get_s16(&fs->fy) * 1000;
   r[2].l.range[0].min = -get_s16(&fs->fz) * 1000;
   r[2].l.range[0].max = get_s16(&fs->fz) * 1000;
   r[3].l.range[0].min = -get_s16(&fs->mx) * 100;
   r[3].l.range[0].max = get_s16(&fs->mx) * 100;
   r[4].l.range[0].min = -get_s16(&fs->my) * 100;
   r[4].l.range[0].max = get_s16(&fs->my) * 100;
   r[5].l.range[0].min = -get_s16(&fs->mz) * 100;
   /* the next five are questionable */
   r[5].l.range[0].max = get_s16(&fs->mz) * 100;
   r[6].l.range[0].min = -get_s16(&fs->v1) * 100;
   r[6].l.range[0].max = get_s16(&fs->v1) * 100;
   r[7].l.range[0].min = -get_s16(&fs->v2) * 100;
   r[7].l.range[0].max = get_s16(&fs->v2) * 100;
   r[8].l.range[0].min = 0;
   r[8].l.range[0].max = 65535;

   use_offset(sensor, 0);
   spriv->state = state_jr3_init_use_offset_complete;
   /* Allow 40 ms for completion */
   result = poll_delay_min_max(40, 100);
  }
  break;
 case state_jr3_init_use_offset_complete:
  if (!is_complete(sensor)) {
   result = poll_delay_min_max(20, 100);
  } else {
   set_s16(&sensor->offsets.fx, 0);
   set_s16(&sensor->offsets.fy, 0);
   set_s16(&sensor->offsets.fz, 0);
   set_s16(&sensor->offsets.mx, 0);
   set_s16(&sensor->offsets.my, 0);
   set_s16(&sensor->offsets.mz, 0);

   set_offset(sensor);

   spriv->state = state_jr3_done;
  }
  break;
 case state_jr3_done:
  result = poll_delay_min_max(10000, 20000);
  break;
 default:
  break;
 }

 return result;
}

static void jr3_pci_poll_dev(struct timer_list *t)
{
 struct jr3_pci_dev_private *devpriv = timer_container_of(devpriv, t,
         timer);
 struct comedi_device *dev = devpriv->dev;
 struct jr3_pci_subdev_private *spriv;
 struct comedi_subdevice *s;
 unsigned long flags;
 unsigned long now;
 int delay;
 int i;

 spin_lock_irqsave(&dev->spinlock, flags);
 delay = 1000;
 now = jiffies;

 /* Poll all sensors that are ready to be polled */
 for (i = 0; i < dev->n_subdevices; i++) {
  s = &dev->subdevices[i];
  spriv = s->private;

  if (time_after_eq(now, spriv->next_time_min)) {
   struct jr3_pci_poll_delay sub_delay;

   sub_delay = jr3_pci_poll_subdevice(s);

   spriv->next_time_min = jiffies +
            msecs_to_jiffies(sub_delay.min);

   if (sub_delay.max && sub_delay.max < delay)
    /*
 * Wake up as late as possible ->
 * poll as many sensors as possible at once.
 */

    delay = sub_delay.max;
  }
 }
 spin_unlock_irqrestore(&dev->spinlock, flags);

 devpriv->timer.expires = jiffies + msecs_to_jiffies(delay);
 add_timer(&devpriv->timer);
}

static struct jr3_pci_subdev_private *
jr3_pci_alloc_spriv(struct comedi_device *dev, struct comedi_subdevice *s)
{
 struct jr3_block __iomem *block = dev->mmio;
 struct jr3_pci_subdev_private *spriv;
 int j;
 int k;

 spriv = comedi_alloc_spriv(s, sizeof(*spriv));
 if (!spriv)
  return NULL;

 spriv->sensor = &block[s->index].sensor;

 for (j = 0; j < 8; j++) {
  spriv->range[j].l.length = 1;
  spriv->range[j].l.range[0].min = -1000000;
  spriv->range[j].l.range[0].max = 1000000;

  for (k = 0; k < 7; k++) {
   spriv->range_table_list[j + k * 8] = &spriv->range[j].l;
   spriv->maxdata_list[j + k * 8] = 0x7fff;
  }
 }
 spriv->range[8].l.length = 1;
 spriv->range[8].l.range[0].min = 0;
 spriv->range[8].l.range[0].max = 65535;

 spriv->range_table_list[56] = &spriv->range[8].l;
 spriv->range_table_list[57] = &spriv->range[8].l;
 spriv->maxdata_list[56] = 0xffff;
 spriv->maxdata_list[57] = 0xffff;

 return spriv;
}

static void jr3_pci_show_copyright(struct comedi_device *dev)
{
 struct jr3_block __iomem *block = dev->mmio;
 struct jr3_sensor __iomem *sensor0 = &block[0].sensor;
 char copy[ARRAY_SIZE(sensor0->copyright) + 1];
 int i;

 for (i = 0; i < ARRAY_SIZE(sensor0->copyright); i++)
  copy[i] = (char)(get_u16(&sensor0->copyright[i]) >> 8);
 copy[i] = '\0';
 dev_dbg(dev->class_dev, "Firmware copyright: %s\n", copy);
}

static int jr3_pci_auto_attach(struct comedi_device *dev,
          unsigned long context)
{
 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 static const struct jr3_pci_board *board;
 struct jr3_pci_dev_private *devpriv;
 struct jr3_pci_subdev_private *spriv;
 struct jr3_block __iomem *block;
 struct comedi_subdevice *s;
 int ret;
 int i;

 BUILD_BUG_ON(sizeof(struct jr3_block) != 0x80000);

 if (context < ARRAY_SIZE(jr3_pci_boards))
  board = &jr3_pci_boards[context];
 if (!board)
  return -ENODEV;
 dev->board_ptr = board;
 dev->board_name = board->name;

 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 if (!devpriv)
  return -ENOMEM;

 ret = comedi_pci_enable(dev);
 if (ret)
  return ret;

 if (pci_resource_len(pcidev, 0) < board->n_subdevs * sizeof(*block))
  return -ENXIO;

 dev->mmio = pci_ioremap_bar(pcidev, 0);
 if (!dev->mmio)
  return -ENOMEM;

 block = dev->mmio;

 ret = comedi_alloc_subdevices(dev, board->n_subdevs);
 if (ret)
  return ret;

 dev->open = jr3_pci_open;
 for (i = 0; i < dev->n_subdevices; i++) {
  s = &dev->subdevices[i];
  s->type  = COMEDI_SUBD_AI;
  s->subdev_flags = SDF_READABLE | SDF_GROUND;
  s->n_chan = 8 * 7 + 2;
  s->insn_read = jr3_pci_ai_insn_read;

  spriv = jr3_pci_alloc_spriv(dev, s);
  if (!spriv)
   return -ENOMEM;

  /* Channel specific range and maxdata */
  s->range_table_list = spriv->range_table_list;
  s->maxdata_list  = spriv->maxdata_list;
 }

 /* Reset DSP card */
 for (i = 0; i < dev->n_subdevices; i++)
  writel(0, &block[i].reset);

 ret = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev,
       "comedi/jr3pci.idm",
       jr3_download_firmware, 0);
 dev_dbg(dev->class_dev, "Firmware load %d\n", ret);
 if (ret < 0)
  return ret;
 /*
 * TODO: use firmware to load preferred offset tables. Suggested
 * format:
 *     model serial Fx Fy Fz Mx My Mz\n
 *
 *     comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev,
 *                          "comedi/jr3_offsets_table",
 *                          jr3_download_firmware, 1);
 */


 /*
 * It takes a few milliseconds for software to settle as much as we
 * can read firmware version
 */

 msleep_interruptible(25);
 jr3_pci_show_copyright(dev);

 /* Start card timer */
 for (i = 0; i < dev->n_subdevices; i++) {
  s = &dev->subdevices[i];
  spriv = s->private;

  spriv->next_time_min = jiffies + msecs_to_jiffies(500);
 }

 devpriv->dev = dev;
 timer_setup(&devpriv->timer, jr3_pci_poll_dev, 0);
 devpriv->timer.expires = jiffies + msecs_to_jiffies(1000);
 add_timer(&devpriv->timer);

 return 0;
}

static void jr3_pci_detach(struct comedi_device *dev)
{
 struct jr3_pci_dev_private *devpriv = dev->private;

 if (devpriv)
  timer_shutdown_sync(&devpriv->timer);

 comedi_pci_detach(dev);
}

static struct comedi_driver jr3_pci_driver = {
 .driver_name = "jr3_pci",
 .module  = THIS_MODULE,
 .auto_attach = jr3_pci_auto_attach,
 .detach  = jr3_pci_detach,
};

static int jr3_pci_pci_probe(struct pci_dev *dev,
        const struct pci_device_id *id)
{
 return comedi_pci_auto_config(dev, &jr3_pci_driver, id->driver_data);
}

static const struct pci_device_id jr3_pci_pci_table[] = {
 { PCI_VDEVICE(JR3, 0x1111), BOARD_JR3_1 },
 { PCI_VDEVICE(JR3, 0x3111), BOARD_JR3_1 },
 { PCI_VDEVICE(JR3, 0x3112), BOARD_JR3_2 },
 { PCI_VDEVICE(JR3, 0x3113), BOARD_JR3_3 },
 { PCI_VDEVICE(JR3, 0x3114), BOARD_JR3_4 },
 { 0 }
};
MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table);

static struct pci_driver jr3_pci_pci_driver = {
 .name  = "jr3_pci",
 .id_table = jr3_pci_pci_table,
 .probe  = jr3_pci_pci_probe,
 .remove  = comedi_pci_auto_unconfig,
};
module_comedi_pci_driver(jr3_pci_driver, jr3_pci_pci_driver);

MODULE_AUTHOR("Comedi https://www.comedi.org");
MODULE_DESCRIPTION("Comedi driver for JR3/PCI force sensor board");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE("comedi/jr3pci.idm");

Messung V0.5
C=94 H=93 G=93

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.