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 13 kB image not shown  

Quelle  dt2801.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * comedi/drivers/dt2801.c
 * Device Driver for DataTranslation DT2801
 *
 */

/*
 * Driver: dt2801
 * Description: Data Translation DT2801 series and DT01-EZ
 * Author: ds
 * Status: works
 * Devices: [Data Translation] DT2801 (dt2801), DT2801-A, DT2801/5716A,
 * DT2805, DT2805/5716A, DT2808, DT2818, DT2809, DT01-EZ
 *
 * This driver can autoprobe the type of board.
 *
 * Configuration options:
 * [0] - I/O port base address
 * [1] - unused
 * [2] - A/D reference 0=differential, 1=single-ended
 * [3] - A/D range
 *   0 = [-10, 10]
 *   1 = [0,10]
 * [4] - D/A 0 range
 *   0 = [-10, 10]
 *   1 = [-5,5]
 *   2 = [-2.5,2.5]
 *   3 = [0,10]
 *   4 = [0,5]
 * [5] - D/A 1 range (same choices)
 */


#include <linux/module.h>
#include <linux/comedi/comedidev.h>
#include <linux/delay.h>

#define DT2801_TIMEOUT 1000

/* Hardware Configuration */
/* ====================== */

#define DT2801_MAX_DMA_SIZE (64 * 1024)

/* define's */
/* ====================== */

/* Commands */
#define DT_C_RESET       0x0
#define DT_C_CLEAR_ERR   0x1
#define DT_C_READ_ERRREG 0x2
#define DT_C_SET_CLOCK   0x3

#define DT_C_TEST        0xb
#define DT_C_STOP        0xf

#define DT_C_SET_DIGIN   0x4
#define DT_C_SET_DIGOUT  0x5
#define DT_C_READ_DIG    0x6
#define DT_C_WRITE_DIG   0x7

#define DT_C_WRITE_DAIM  0x8
#define DT_C_SET_DA      0x9
#define DT_C_WRITE_DA    0xa

#define DT_C_READ_ADIM   0xc
#define DT_C_SET_AD      0xd
#define DT_C_READ_AD     0xe

/*
 * Command modifiers (only used with read/write), EXTTRIG can be
 * used with some other commands.
 */

#define DT_MOD_DMA     BIT(4)
#define DT_MOD_CONT    BIT(5)
#define DT_MOD_EXTCLK  BIT(6)
#define DT_MOD_EXTTRIG BIT(7)

/* Bits in status register */
#define DT_S_DATA_OUT_READY   BIT(0)
#define DT_S_DATA_IN_FULL     BIT(1)
#define DT_S_READY            BIT(2)
#define DT_S_COMMAND          BIT(3)
#define DT_S_COMPOSITE_ERROR  BIT(7)

/* registers */
#define DT2801_DATA  0
#define DT2801_STATUS  1
#define DT2801_CMD  1

#if 0
/* ignore 'defined but not used' warning */
static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = {
 4, {
  BIP_RANGE(10),
  BIP_RANGE(5),
  BIP_RANGE(2.5),
  BIP_RANGE(1.25)
 }
};
#endif
static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = {
 4, {
  BIP_RANGE(10),
  BIP_RANGE(1),
  BIP_RANGE(0.1),
  BIP_RANGE(0.02)
 }
};

#if 0
/* ignore 'defined but not used' warning */
static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = {
 4, {
  UNI_RANGE(10),
  UNI_RANGE(5),
  UNI_RANGE(2.5),
  UNI_RANGE(1.25)
 }
};
#endif
static const struct comedi_lrange range_dt2801_ai_pgl_unipolar = {
 4, {
  UNI_RANGE(10),
  UNI_RANGE(1),
  UNI_RANGE(0.1),
  UNI_RANGE(0.02)
 }
};

struct dt2801_board {
 const char *name;
 int boardcode;
 int ad_diff;
 int ad_chan;
 int adbits;
 int adrangetype;
 int dabits;
};

/*
 * Typeid's for the different boards of the DT2801-series
 * (taken from the test-software, that comes with the board)
 */

static const struct dt2801_board boardtypes[] = {
 {
  .name = "dt2801",
  .boardcode = 0x09,
  .ad_diff = 2,
  .ad_chan = 16,
  .adbits = 12,
  .adrangetype = 0,
  .dabits = 12},
 {
  .name = "dt2801-a",
  .boardcode = 0x52,
  .ad_diff = 2,
  .ad_chan = 16,
  .adbits = 12,
  .adrangetype = 0,
  .dabits = 12},
 {
  .name = "dt2801/5716a",
  .boardcode = 0x82,
  .ad_diff = 1,
  .ad_chan = 16,
  .adbits = 16,
  .adrangetype = 1,
  .dabits = 12},
 {
  .name = "dt2805",
  .boardcode = 0x12,
  .ad_diff = 1,
  .ad_chan = 16,
  .adbits = 12,
  .adrangetype = 0,
  .dabits = 12},
 {
  .name = "dt2805/5716a",
  .boardcode = 0x92,
  .ad_diff = 1,
  .ad_chan = 16,
  .adbits = 16,
  .adrangetype = 1,
  .dabits = 12},
 {
  .name = "dt2808",
  .boardcode = 0x20,
  .ad_diff = 0,
  .ad_chan = 16,
  .adbits = 12,
  .adrangetype = 2,
  .dabits = 8},
 {
  .name = "dt2818",
  .boardcode = 0xa2,
  .ad_diff = 0,
  .ad_chan = 4,
  .adbits = 12,
  .adrangetype = 0,
  .dabits = 12},
 {
  .name = "dt2809",
  .boardcode = 0xb0,
  .ad_diff = 0,
  .ad_chan = 8,
  .adbits = 12,
  .adrangetype = 1,
  .dabits = 12},
};

struct dt2801_private {
 const struct comedi_lrange *dac_range_types[2];
};

/*
 * These are the low-level routines:
 * writecommand: write a command to the board
 * writedata: write data byte
 * readdata: read data byte
 */


/*
 * Only checks DataOutReady-flag, not the Ready-flag as it is done
 *  in the examples of the manual. I don't see why this should be
 *  necessary.
 */

static int dt2801_readdata(struct comedi_device *dev, int *data)
{
 int stat = 0;
 int timeout = DT2801_TIMEOUT;

 do {
  stat = inb_p(dev->iobase + DT2801_STATUS);
  if (stat & (DT_S_COMPOSITE_ERROR | DT_S_READY))
   return stat;
  if (stat & DT_S_DATA_OUT_READY) {
   *data = inb_p(dev->iobase + DT2801_DATA);
   return 0;
  }
 } while (--timeout > 0);

 return -ETIME;
}

static int dt2801_readdata2(struct comedi_device *dev, int *data)
{
 int lb = 0;
 int hb = 0;
 int ret;

 ret = dt2801_readdata(dev, &lb);
 if (ret)
  return ret;
 ret = dt2801_readdata(dev, &hb);
 if (ret)
  return ret;

 *data = (hb << 8) + lb;
 return 0;
}

static int dt2801_writedata(struct comedi_device *dev, unsigned int data)
{
 int stat = 0;
 int timeout = DT2801_TIMEOUT;

 do {
  stat = inb_p(dev->iobase + DT2801_STATUS);

  if (stat & DT_S_COMPOSITE_ERROR)
   return stat;
  if (!(stat & DT_S_DATA_IN_FULL)) {
   outb_p(data & 0xff, dev->iobase + DT2801_DATA);
   return 0;
  }
 } while (--timeout > 0);

 return -ETIME;
}

static int dt2801_writedata2(struct comedi_device *dev, unsigned int data)
{
 int ret;

 ret = dt2801_writedata(dev, data & 0xff);
 if (ret < 0)
  return ret;
 ret = dt2801_writedata(dev, data >> 8);
 if (ret < 0)
  return ret;

 return 0;
}

static int dt2801_wait_for_ready(struct comedi_device *dev)
{
 int timeout = DT2801_TIMEOUT;
 int stat;

 stat = inb_p(dev->iobase + DT2801_STATUS);
 if (stat & DT_S_READY)
  return 0;
 do {
  stat = inb_p(dev->iobase + DT2801_STATUS);

  if (stat & DT_S_COMPOSITE_ERROR)
   return stat;
  if (stat & DT_S_READY)
   return 0;
 } while (--timeout > 0);

 return -ETIME;
}

static void dt2801_writecmd(struct comedi_device *dev, int command)
{
 int stat;

 dt2801_wait_for_ready(dev);

 stat = inb_p(dev->iobase + DT2801_STATUS);
 if (stat & DT_S_COMPOSITE_ERROR) {
  dev_dbg(dev->class_dev,
   "composite-error in %s, ignoring\n", __func__);
 }
 if (!(stat & DT_S_READY))
  dev_dbg(dev->class_dev, "!ready in %s, ignoring\n", __func__);
 outb_p(command, dev->iobase + DT2801_CMD);
}

static int dt2801_reset(struct comedi_device *dev)
{
 int board_code = 0;
 unsigned int stat;
 int timeout;

 /* pull random data from data port */
 inb_p(dev->iobase + DT2801_DATA);
 inb_p(dev->iobase + DT2801_DATA);
 inb_p(dev->iobase + DT2801_DATA);
 inb_p(dev->iobase + DT2801_DATA);

 /* dt2801_writecmd(dev,DT_C_STOP); */
 outb_p(DT_C_STOP, dev->iobase + DT2801_CMD);

 /* dt2801_wait_for_ready(dev); */
 usleep_range(100, 200);
 timeout = 10000;
 do {
  stat = inb_p(dev->iobase + DT2801_STATUS);
  if (stat & DT_S_READY)
   break;
 } while (timeout--);
 if (!timeout)
  dev_dbg(dev->class_dev, "timeout 1 status=0x%02x\n", stat);

 /* dt2801_readdata(dev,&board_code); */

 outb_p(DT_C_RESET, dev->iobase + DT2801_CMD);
 /* dt2801_writecmd(dev,DT_C_RESET); */

 usleep_range(100, 200);
 timeout = 10000;
 do {
  stat = inb_p(dev->iobase + DT2801_STATUS);
  if (stat & DT_S_READY)
   break;
 } while (timeout--);
 if (!timeout)
  dev_dbg(dev->class_dev, "timeout 2 status=0x%02x\n", stat);

 dt2801_readdata(dev, &board_code);

 return board_code;
}

static int probe_number_of_ai_chans(struct comedi_device *dev)
{
 int n_chans;
 int stat;
 int data;

 for (n_chans = 0; n_chans < 16; n_chans++) {
  dt2801_writecmd(dev, DT_C_READ_ADIM);
  dt2801_writedata(dev, 0);
  dt2801_writedata(dev, n_chans);
  stat = dt2801_readdata2(dev, &data);

  if (stat)
   break;
 }

 dt2801_reset(dev);
 dt2801_reset(dev);

 return n_chans;
}

static const struct comedi_lrange *dac_range_table[] = {
 &range_bipolar10,
 &range_bipolar5,
 &range_bipolar2_5,
 &range_unipolar10,
 &range_unipolar5
};

static const struct comedi_lrange *dac_range_lkup(int opt)
{
 if (opt < 0 || opt >= 5)
  return &range_unknown;
 return dac_range_table[opt];
}

static const struct comedi_lrange *ai_range_lkup(int type, int opt)
{
 switch (type) {
 case 0:
  return (opt) ?
      &range_dt2801_ai_pgl_unipolar :
      &range_dt2801_ai_pgl_bipolar;
 case 1:
  return (opt) ? &range_unipolar10 : &range_bipolar10;
 case 2:
  return &range_unipolar5;
 }
 return &range_unknown;
}

static int dt2801_error(struct comedi_device *dev, int stat)
{
 if (stat < 0) {
  if (stat == -ETIME)
   dev_dbg(dev->class_dev, "timeout\n");
  else
   dev_dbg(dev->class_dev, "error %d\n", stat);
  return stat;
 }
 dev_dbg(dev->class_dev, "error status 0x%02x, resetting...\n", stat);

 dt2801_reset(dev);
 dt2801_reset(dev);

 return -EIO;
}

static int dt2801_ai_insn_read(struct comedi_device *dev,
          struct comedi_subdevice *s,
          struct comedi_insn *insn, unsigned int *data)
{
 int d;
 int stat;
 int i;

 for (i = 0; i < insn->n; i++) {
  dt2801_writecmd(dev, DT_C_READ_ADIM);
  dt2801_writedata(dev, CR_RANGE(insn->chanspec));
  dt2801_writedata(dev, CR_CHAN(insn->chanspec));
  stat = dt2801_readdata2(dev, &d);

  if (stat != 0)
   return dt2801_error(dev, stat);

  data[i] = d;
 }

 return i;
}

static int dt2801_ao_insn_write(struct comedi_device *dev,
    struct comedi_subdevice *s,
    struct comedi_insn *insn,
    unsigned int *data)
{
 unsigned int chan = CR_CHAN(insn->chanspec);

 dt2801_writecmd(dev, DT_C_WRITE_DAIM);
 dt2801_writedata(dev, chan);
 dt2801_writedata2(dev, data[0]);

 s->readback[chan] = data[0];

 return 1;
}

static int dt2801_dio_insn_bits(struct comedi_device *dev,
    struct comedi_subdevice *s,
    struct comedi_insn *insn,
    unsigned int *data)
{
 int which = (s == &dev->subdevices[3]) ? 1 : 0;
 unsigned int val = 0;

 if (comedi_dio_update_state(s, data)) {
  dt2801_writecmd(dev, DT_C_WRITE_DIG);
  dt2801_writedata(dev, which);
  dt2801_writedata(dev, s->state);
 }

 dt2801_writecmd(dev, DT_C_READ_DIG);
 dt2801_writedata(dev, which);
 dt2801_readdata(dev, &val);

 data[1] = val;

 return insn->n;
}

static int dt2801_dio_insn_config(struct comedi_device *dev,
      struct comedi_subdevice *s,
      struct comedi_insn *insn,
      unsigned int *data)
{
 int ret;

 ret = comedi_dio_insn_config(dev, s, insn, data, 0xff);
 if (ret)
  return ret;

 dt2801_writecmd(dev, s->io_bits ? DT_C_SET_DIGOUT : DT_C_SET_DIGIN);
 dt2801_writedata(dev, (s == &dev->subdevices[3]) ? 1 : 0);

 return insn->n;
}

/*
 * options:
 * [0] - i/o base
 * [1] - unused
 * [2] - a/d 0=differential, 1=single-ended
 * [3] - a/d range 0=[-10,10], 1=[0,10]
 * [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
 * [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
 */

static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
 const struct dt2801_board *board;
 struct dt2801_private *devpriv;
 struct comedi_subdevice *s;
 int board_code, type;
 int ret = 0;
 int n_ai_chans;

 ret = comedi_request_region(dev, it->options[0], 0x2);
 if (ret)
  return ret;

 /* do some checking */

 board_code = dt2801_reset(dev);

 /* heh.  if it didn't work, try it again. */
 if (!board_code)
  board_code = dt2801_reset(dev);

 for (type = 0; type < ARRAY_SIZE(boardtypes); type++) {
  if (boardtypes[type].boardcode == board_code)
   goto havetype;
 }
 dev_dbg(dev->class_dev,
  "unrecognized board code=0x%02x, contact author\n", board_code);
 type = 0;

havetype:
 dev->board_ptr = boardtypes + type;
 board = dev->board_ptr;

 n_ai_chans = probe_number_of_ai_chans(dev);

 ret = comedi_alloc_subdevices(dev, 4);
 if (ret)
  goto out;

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

 dev->board_name = board->name;

 s = &dev->subdevices[0];
 /* ai subdevice */
 s->type = COMEDI_SUBD_AI;
 s->subdev_flags = SDF_READABLE | SDF_GROUND;
#if 1
 s->n_chan = n_ai_chans;
#else
 if (it->options[2])
  s->n_chan = board->ad_chan;
 else
  s->n_chan = board->ad_chan / 2;
#endif
 s->maxdata = (1 << board->adbits) - 1;
 s->range_table = ai_range_lkup(board->adrangetype, it->options[3]);
 s->insn_read = dt2801_ai_insn_read;

 s = &dev->subdevices[1];
 /* ao subdevice */
 s->type = COMEDI_SUBD_AO;
 s->subdev_flags = SDF_WRITABLE;
 s->n_chan = 2;
 s->maxdata = (1 << board->dabits) - 1;
 s->range_table_list = devpriv->dac_range_types;
 devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]);
 devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]);
 s->insn_write = dt2801_ao_insn_write;

 ret = comedi_alloc_subdev_readback(s);
 if (ret)
  return ret;

 s = &dev->subdevices[2];
 /* 1st digital subdevice */
 s->type = COMEDI_SUBD_DIO;
 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 s->n_chan = 8;
 s->maxdata = 1;
 s->range_table = &range_digital;
 s->insn_bits = dt2801_dio_insn_bits;
 s->insn_config = dt2801_dio_insn_config;

 s = &dev->subdevices[3];
 /* 2nd digital subdevice */
 s->type = COMEDI_SUBD_DIO;
 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 s->n_chan = 8;
 s->maxdata = 1;
 s->range_table = &range_digital;
 s->insn_bits = dt2801_dio_insn_bits;
 s->insn_config = dt2801_dio_insn_config;

 ret = 0;
out:
 return ret;
}

static struct comedi_driver dt2801_driver = {
 .driver_name = "dt2801",
 .module  = THIS_MODULE,
 .attach  = dt2801_attach,
 .detach  = comedi_legacy_detach,
};
module_comedi_driver(dt2801_driver);

MODULE_AUTHOR("Comedi https://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");

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

¤ Dauer der Verarbeitung: 0.6 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.