Added Advantech PCI-1723 driver by yonggang <rsmgnu at gmail dot com>.
authorIan Abbott <abbotti@mev.co.uk>
Tue, 25 Mar 2008 11:56:07 +0000 (11:56 +0000)
committerIan Abbott <abbotti@mev.co.uk>
Tue, 25 Mar 2008 11:56:07 +0000 (11:56 +0000)
comedi/drivers/Kbuild
comedi/drivers/Makefile.am
comedi/drivers/adv_pci1723.c [new file with mode: 0644]

index b90fe145d0ed672e21dba727023096bfa0155bfc..d0546cec75012c4bb9b7b97f94f64dfcd75d216a 100644 (file)
@@ -49,6 +49,7 @@ obj-m += adl_pci9111.o
 obj-m += adl_pci9118.o
 obj-m += adq12b.o
 obj-m += adv_pci1710.o
+obj-m += adv_pci1723.o
 obj-m += adv_pci_dio.o
 obj-m += aio_aio12_8.o
 obj-m += aio_iiro_16.o
index deb700357da58f26eb4d6433a23d894c17237565..8f5455004c3e6e929809e31bbf470594016a4348 100644 (file)
@@ -120,6 +120,7 @@ module_PROGRAMS = \
  adl_pci9118.ko \
  adq12b.ko \
  adv_pci1710.ko \
+ adv_pci1723.ko \
  adv_pci_dio.ko \
  amplc_pci224.ko \
  amplc_pci230.ko \
@@ -230,6 +231,7 @@ adl_pci9111_ko_SOURCES = adl_pci9111.c
 adl_pci9118_ko_SOURCES = adl_pci9118.c
 adq12b_ko_SOURCES = adq12b.c
 adv_pci1710_ko_SOURCES = adv_pci1710.c
+adv_pci1723_ko_SOURCES = adv_pci1723.c
 adv_pci_dio_ko_SOURCES = adv_pci_dio.c
 aio_aio12_8_ko_SOURCES = aio_aio12_8.c
 aio_iiro_16_ko_SOURCES = aio_iiro_16.c
diff --git a/comedi/drivers/adv_pci1723.c b/comedi/drivers/adv_pci1723.c
new file mode 100644 (file)
index 0000000..bf3efa1
--- /dev/null
@@ -0,0 +1,467 @@
+/***************************************************************************************************
+   comedi/drivers/pci1723.c
+
+   COMEDI - Linux Control and Measurement Device Interface
+   Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+**************************************************************************************************/
+/*
+Driver:       adv_pci1723
+Description:  the driver of adv pci-1723
+Devices:      pci-1723
+Author:       yonggang & Ian Abbott 
+Email:        rsmgnu@gmail.com
+Updated:      2008-03-20
+Status:       works
+
+Configuration Options:  none
+*/
+
+
+#include <linux/comedidev.h>
+
+#include <linux/pci.h>                  /* for PCI devices */
+
+#define ADVANTECH_VENDOR        0x13fe  /* Advantech PCI vendor ID */
+
+// hardware types of the cards
+#define TYPE_PCI1723 0
+
+#define IORANGE_1723  0x2A
+
+/* all the registers for the pci1723 board */
+#define PCI1723_DA(N)   ((N)<<1)                /* W:   D/A register N (0 to 7) */
+
+#define PCI1723_SYN_SET  0x12                   /*synchronized set register       */
+#define PCI1723_ALL_CHNNELE_SYN_STROBE  0x12    /*synchronized status register    */
+
+#define PCI1723_RANGE_CALIBRATION_MODE 0x14     /* range and calibration mode   */
+#define PCI1723_RANGE_CALIBRATION_STATUS 0x14   /* range and calibration status */
+
+#define PCI1723_CONTROL_CMD_CALIBRATION_FUN 0x16 /* SADC control command for calibration function */
+#define PCI1723_STATUS_CMD_CALIBRATION_FUN 0x16  /* SADC control status for calibration function */
+
+#define PCI1723_CALIBRATION_PARA_STROBE 0x18    /* Calibration parameter strobe */
+
+#define PCI1723_DIGITAL_IO_PORT_SET 0x1A        /* Digital I/O port setting */
+#define PCI1723_DIGITAL_IO_PORT_MODE 0x1A       /* Digital I/O port mode*/
+
+#define PCI1723_WRITE_DIGITAL_OUTPUT_CMD 0x1C   /* Write digital output command */
+#define PCI1723_READ_DIGITAL_INPUT_DATA 0x1C    /* Read digital input data */
+
+#define PCI1723_WRITE_CAL_CMD 0x1E              /* Write calibration command */
+#define PCI1723_READ_CAL_STATUS 0x1E            /* Read calibration status */
+
+#define PCI1723_SYN_STROBE 0x20                 /* Synchronized strobe */
+
+#define PCI1723_RESET_ALL_CHN_STROBE 0x22       /* Reset all D/A channels strobe */
+
+#define PCI1723_RESET_CAL_CONTROL_STROBE 0x24   /* Reset the calibration controller strobe */
+
+#define PCI1723_CHANGE_CHA_OUTPUT_TYPE_STROBE 0x26/* Change D/A channels output type strobe */
+
+#define PCI1723_SELECT_CALIBRATION 0x28         /* Select the calibration Ref_V */
+
+//static unsigned short pci_list_builded=0;     /*=1 list of card is know */
+
+static const comedi_lrange range_pci1723={ 1, {
+       BIP_RANGE(10)
+       }
+};
+
+/*
+ * Board descriptions for pci1723 boards.
+ */
+typedef struct pci1723_board_struct {
+       const char *name;
+       int     vendor_id;      // PCI vendor a device ID of card
+       int     device_id;
+       int   iorange;
+       char  cardtype;
+       int     n_aochan;       // num of D/A chans
+       int     n_diochan;      // num of DIO chans
+       int   ao_maxdata;       // resolution of D/A
+     const comedi_lrange *rangelist_ao; // rangelist for D/A
+}boardtype;
+
+static const boardtype boardtypes[] =
+{
+   {
+       name: "pci1723",
+       vendor_id: ADVANTECH_VENDOR,
+       device_id: 0x1723,
+       iorange: IORANGE_1723,
+       cardtype: TYPE_PCI1723,
+       n_aochan: 8,
+       n_diochan: 16,
+       ao_maxdata: 0xffff,
+       rangelist_ao: &range_pci1723
+   },
+};
+
+/* This is used by modprobe to translate PCI IDs to drivers.  Should
+ * only be used for PCI and ISA-PnP devices */
+static struct pci_device_id pci1723_pci_table[] = __devinitdata{
+       {PCI_VENDOR_ID_ADVANTECH, 0x1723, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0}
+};
+
+MODULE_DEVICE_TABLE(pci, pci1723_pci_table);
+
+/*
+ * The comedi_driver structure tells the Comedi core module
+ * which functions to call to configure/deconfigure (attach/detach)
+ * the board, and also about the kernel module that contains
+ * the device code.
+ */
+static int pci1723_attach(comedi_device * dev, comedi_devconfig * it);
+static int pci1723_detach(comedi_device * dev);
+
+#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))
+
+static comedi_driver driver_pci1723 = {
+     driver_name:"adv_pci1723",
+     module:THIS_MODULE,
+     attach:pci1723_attach,
+     detach:pci1723_detach,
+     num_names:n_boardtypes,
+     board_name:&boardtypes[0].name,
+     offset:sizeof(boardtype),
+};
+
+/* this structure is for data unique to this hardware driver. */
+typedef struct {
+       int valid;                      //card is usable;
+
+       struct pci_dev *pcidev;
+       unsigned char  da_range[8];     // D/A output range for each channel
+
+       sampl_t ao_data[8];             // data output buffer
+} pci1723_private;
+
+
+/*the following macro to make it easy to
+* access the private structure.
+*/
+#define devpriv ((pci1723_private *)dev->private)
+
+#define this_board ((const boardtype *)dev->board_ptr)
+
+
+
+/*
+ *   the pci1723 card reset;
+ */
+static int pci1723_reset(comedi_device * dev)
+{
+       int i;
+       rt_printk("adv_pci1723 EDBG: BGN: pci1723_reset(...)\n");
+
+       outw(0x01, dev->iobase + PCI1723_SYN_SET);                      // set synchronous output mode
+
+       for (i = 0; i < 8; i++) {
+               // set all outputs to 0V
+               devpriv->ao_data[i] = 0x8000;
+               outw(devpriv->ao_data[i], dev->iobase + PCI1723_DA(i));
+               // set all ranges to +/- 10V
+               devpriv->da_range[i] = 0;
+               outw(((devpriv->da_range[i] << 4) | i), PCI1723_RANGE_CALIBRATION_MODE);
+       }
+
+       outw(0, dev->iobase + PCI1723_CHANGE_CHA_OUTPUT_TYPE_STROBE); // update ranges
+       outw(0, dev->iobase + PCI1723_SYN_STROBE);      // update outputs
+
+       // set asynchronous output mode
+       outw(0, dev->iobase + PCI1723_SYN_SET);
+
+       rt_printk("adv_pci1723 EDBG: END: pci1723_reset(...)\n");
+       return 0;
+}
+
+static int pci1723_insn_read_ao(comedi_device * dev, comedi_subdevice * s, comedi_insn *insn, lsampl_t *data)
+{
+       int n,chan;
+
+       chan=CR_CHAN(insn->chanspec);
+       rt_printk(" adv_PCI1723 DEBUG: pci1723_insn_read_ao() ----- \n");
+       for (n=0; n<insn->n; n++)
+               data[n]=devpriv->ao_data[chan];
+
+       return n;
+}
+
+/*
+  analog data output;
+*/
+static int pci1723_ao_write_winsn(comedi_device * dev, comedi_subdevice * s,
+       comedi_insn * insn, lsampl_t * data)
+{
+     int n,chan;
+     chan=CR_CHAN(insn->chanspec);
+
+     rt_printk("PCI1723: the pci1723_ao_write_winsn() ------\n");
+
+     for (n=0; n<insn->n; n++)
+      {
+       
+          devpriv->ao_data[chan]=data[n];
+          outw(data[n], dev->iobase+PCI1723_DA(chan));
+       }
+
+     return n;
+}
+
+/*
+  digital i/o config/query
+*/
+static int pci1723_dio_insn_config(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn, lsampl_t *data)
+{
+       unsigned int mask;
+       unsigned int bits;
+       unsigned short dio_mode;
+
+       mask = 1 << CR_CHAN(insn->chanspec);
+       if (mask & 0x00FF) {
+               bits = 0x00FF;
+       } else {
+               bits = 0xFF00;
+       }
+       switch (data[0]) {
+       case INSN_CONFIG_DIO_INPUT:
+               s->io_bits &= ~bits;
+               break;
+       case INSN_CONFIG_DIO_OUTPUT:
+               s->io_bits |= bits;
+               break;
+       case INSN_CONFIG_DIO_QUERY:
+               data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
+               return insn->n;
+       default:
+               return -EINVAL;
+       }
+
+       // update hardware DIO mode
+       dio_mode = 0x0000;      // low byte output, high byte output
+       if ((s->io_bits & 0x00FF) == 0)
+               dio_mode |= 0x0001;     // low byte input
+       if ((s->io_bits & 0xFF00) == 0)
+               dio_mode |= 0x0002;     // high byte input
+       outw(dio_mode, dev->iobase + PCI1723_DIGITAL_IO_PORT_SET);
+       return 1;
+}
+
+/*
+  digital i/o bits read/write
+*/
+static int pci1723_dio_insn_bits(comedi_device *dev, comedi_subdevice *s,
+       comedi_insn *insn, lsampl_t *data)
+{
+       if (data[0]) {
+               s->state &= ~data[0];
+               s->state |= (data[0] & data[1]);
+               outw(s->state, dev->iobase + PCI1723_WRITE_DIGITAL_OUTPUT_CMD);
+       }
+       data[1] = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA);
+       return 2;
+}
+
+/*
+ * Attach is called by the Comedi core to configure the driver
+ * for a pci1723 board.
+ */
+static int pci1723_attach(comedi_device * dev, comedi_devconfig * it)
+{
+       comedi_subdevice *s;
+       int ret,subdev,n_subdevices;
+       //unsigned short io_addr[5],master,irq;
+       //struct pcilst_struct *card=NULL;
+     struct pci_dev *pcidev;
+     unsigned int iobase;
+       unsigned char pci_bus,pci_slot,pci_func;
+       //int dma;
+       //unsigned long pages;
+       //unsigned long physLas0,physLas1,physLcfg;
+     int opt_bus, opt_slot;
+       const char *errstr;
+
+     rt_printk("comedi%d: adv_pci1723: board=%s",dev->minor,this_board->name);
+
+     opt_bus = it->options[0];
+       opt_slot = it->options[1];
+
+       if((ret=alloc_private(dev,sizeof(pci1723_private)))<0)
+       {
+               rt_printk(" - Allocation failed!\n");
+               return -ENOMEM;
+       }
+
+       /* Look for matching PCI device */
+       errstr = "not found!";
+       pcidev = NULL;
+       while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,this_board->device_id, pcidev)))
+       {
+               /* Found matching vendor/device. */
+               if (opt_bus || opt_slot) {
+                       /* Check bus/slot. */
+                       if (opt_bus != pcidev->bus->number
+                                       || opt_slot != PCI_SLOT(pcidev->devfn))
+                               continue;       /* no match */
+               }
+               /*
+                * Look for device that isn't in use.
+                * Enable PCI device and request regions.
+                */
+               if (pci_enable_device(pcidev)) {
+                       errstr = "failed to enable PCI device!";
+                       continue;
+               }
+               if (pci_request_regions(pcidev, "adl_pci1723")) {
+                       errstr = "in use or I/O port conflict!";
+                       continue;
+               }
+               break;
+       }
+
+       if (!pcidev) {
+               if (opt_bus || opt_slot) {
+                       rt_printk(" - Card at b:s %d:%d %s\n",
+                                       opt_bus, opt_slot, errstr);
+               } else {
+                       rt_printk(" - Card %s\n", errstr);
+               }
+               return -EIO;
+       }
+
+       pci_bus = pcidev->bus->number;
+       pci_slot = PCI_SLOT(pcidev->devfn);
+       pci_func = PCI_FUNC(pcidev->devfn);
+       iobase = pci_resource_start(pcidev, 2);
+
+       rt_printk(", b:s:f=%d:%d:%d, io=0x%4x",pci_bus,pci_slot,pci_func,iobase);
+
+     dev->iobase=iobase;
+
+       dev->board_name = this_board->name;
+       devpriv->pcidev = pcidev;
+
+
+     n_subdevices = 0;
+
+     if (this_board->n_aochan) n_subdevices++;
+     if (this_board->n_diochan) n_subdevices++;
+
+     if((ret=alloc_subdevices(dev, n_subdevices))<0)
+       {
+             rt_printk(" - Allocation failed!\n");
+             return ret;
+       }
+
+       pci1723_reset(dev);
+       subdev = 0;
+       if (this_board->n_aochan)
+       {
+               s = dev->subdevices + subdev;
+               dev->write_subdev = s;
+               s->type = COMEDI_SUBD_AO;
+               s->subdev_flags = SDF_WRITEABLE|SDF_GROUND|SDF_COMMON;
+               s->n_chan = this_board->n_aochan;
+               s->maxdata = this_board->ao_maxdata;
+               s->len_chanlist = this_board->n_aochan;
+            s->range_table = this_board->rangelist_ao;
+
+               s->insn_write=pci1723_ao_write_winsn;
+            s->insn_read=pci1723_insn_read_ao;
+
+               // read DIO config
+               switch (inw(dev->iobase + PCI1723_DIGITAL_IO_PORT_MODE) & 0x03) {
+               case 0x00:      // low byte output, high byte output
+                       s->io_bits = 0xFFFF;
+                       break;
+               case 0x01:      // low byte input, high byte output
+                       s->io_bits = 0xFF00;
+                       break;
+               case 0x02:      // low byte output, high byte input
+                       s->io_bits = 0x00FF;
+                       break;
+               case 0x03:      // low byte input, high byte input
+                       s->io_bits = 0x0000;
+                       break;
+               }
+               // read DIO port state
+               s->state = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA);
+
+               subdev++;
+       }
+
+       if (this_board->n_diochan)
+       {
+               s = dev->subdevices + subdev;
+               s->type = COMEDI_SUBD_DIO;
+               s->subdev_flags = SDF_READABLE|SDF_WRITABLE|SDF_GROUND|SDF_COMMON;
+               s->n_chan = this_board->n_diochan;
+               s->maxdata = 1;
+               s->len_chanlist = this_board->n_diochan;
+               s->range_table = &range_digital;
+               s->insn_config = pci1723_dio_insn_config;
+               s->insn_bits = pci1723_dio_insn_bits;
+               subdev++;
+       }
+
+       devpriv->valid=1;
+
+       pci1723_reset(dev);
+
+       return 0;
+}
+
+/*
+ * _detach is called to deconfigure a device.  It should deallocate
+ * resources.
+ * This function is also called when _attach() fails, so it should be
+ * careful not to release resources that were not necessarily
+ * allocated by _attach().  dev->private and dev->subdevices are
+ * deallocated automatically by the core.
+ */
+static int pci1723_detach(comedi_device * dev)
+{
+       printk("comedi%d: pci1723: remove\n", dev->minor);
+
+       if (dev->private)
+       {
+               if (devpriv->valid)
+                       pci1723_reset(dev);
+
+               if (devpriv->pcidev)
+               {
+                       if (dev->iobase)
+                       {
+                        pci_release_regions(devpriv->pcidev);
+                               pci_disable_device(devpriv->pcidev);
+                       }
+                       pci_dev_put(devpriv->pcidev);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * A convenient macro that defines init_module() and cleanup_module(),
+ * as necessary.
+ */
+COMEDI_INITCLEANUP(driver_pci1723);