diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/icp_multi.c')
-rw-r--r-- | drivers/staging/comedi/drivers/icp_multi.c | 517 |
1 files changed, 147 insertions, 370 deletions
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index 1e104ebf8057..28cf53e48b8d 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -1,94 +1,89 @@ /* - comedi/drivers/icp_multi.c - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1997-2002 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. -*/ + * icp_multi.c + * Comedi driver for Inova ICP_MULTI board + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-2002 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. + */ /* -Driver: icp_multi -Description: Inova ICP_MULTI -Author: Anne Smorthit <anne.smorthit@sfwte.ch> -Devices: [Inova] ICP_MULTI (icp_multi) -Status: works - -The driver works for analog input and output and digital input and output. -It does not work with interrupts or with the counters. Currently no support -for DMA. - -It has 16 single-ended or 8 differential Analogue Input channels with 12-bit -resolution. Ranges : 5V, 10V, +/-5V, +/-10V, 0..20mA and 4..20mA. Input -ranges can be individually programmed for each channel. Voltage or current -measurement is selected by jumper. - -There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V - -16 x Digital Inputs, 24V - -8 x Digital Outputs, 24V, 1A - -4 x 16-bit counters - -Configuration options: not applicable, uses PCI auto config -*/ + * Driver: icp_multi + * Description: Inova ICP_MULTI + * Devices: [Inova] ICP_MULTI (icp_multi) + * Author: Anne Smorthit <anne.smorthit@sfwte.ch> + * Status: works + * + * Configuration options: not applicable, uses PCI auto config + * + * The driver works for analog input and output and digital input and + * output. It does not work with interrupts or with the counters. Currently + * no support for DMA. + * + * It has 16 single-ended or 8 differential Analogue Input channels with + * 12-bit resolution. Ranges : 5V, 10V, +/-5V, +/-10V, 0..20mA and 4..20mA. + * Input ranges can be individually programmed for each channel. Voltage or + * current measurement is selected by jumper. + * + * There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V + * + * 16 x Digital Inputs, 24V + * + * 8 x Digital Outputs, 24V, 1A + * + * 4 x 16-bit counters - not implemented + */ #include <linux/module.h> #include <linux/delay.h> -#include <linux/interrupt.h> #include "../comedi_pci.h" -#define ICP_MULTI_ADC_CSR 0 /* R/W: ADC command/status register */ +#define ICP_MULTI_ADC_CSR 0x00 /* R/W: ADC command/status register */ +#define ICP_MULTI_ADC_CSR_ST BIT(0) /* Start ADC */ +#define ICP_MULTI_ADC_CSR_BSY BIT(0) /* ADC busy */ +#define ICP_MULTI_ADC_CSR_BI BIT(4) /* Bipolar input range */ +#define ICP_MULTI_ADC_CSR_RA BIT(5) /* Input range 0 = 5V, 1 = 10V */ +#define ICP_MULTI_ADC_CSR_DI BIT(6) /* Input mode 1 = differential */ +#define ICP_MULTI_ADC_CSR_DI_CHAN(x) (((x) & 0x7) << 9) +#define ICP_MULTI_ADC_CSR_SE_CHAN(x) (((x) & 0xf) << 8) #define ICP_MULTI_AI 2 /* R: Analogue input data */ -#define ICP_MULTI_DAC_CSR 4 /* R/W: DAC command/status register */ +#define ICP_MULTI_DAC_CSR 0x04 /* R/W: DAC command/status register */ +#define ICP_MULTI_DAC_CSR_ST BIT(0) /* Start DAC */ +#define ICP_MULTI_DAC_CSR_BSY BIT(0) /* DAC busy */ +#define ICP_MULTI_DAC_CSR_BI BIT(4) /* Bipolar output range */ +#define ICP_MULTI_DAC_CSR_RA BIT(5) /* Output range 0 = 5V, 1 = 10V */ +#define ICP_MULTI_DAC_CSR_CHAN(x) (((x) & 0x3) << 8) #define ICP_MULTI_AO 6 /* R/W: Analogue output data */ #define ICP_MULTI_DI 8 /* R/W: Digital inputs */ #define ICP_MULTI_DO 0x0A /* R/W: Digital outputs */ -#define ICP_MULTI_INT_EN 0x0C /* R/W: Interrupt enable register */ -#define ICP_MULTI_INT_STAT 0x0E /* R/W: Interrupt status register */ +#define ICP_MULTI_INT_EN 0x0c /* R/W: Interrupt enable register */ +#define ICP_MULTI_INT_STAT 0x0e /* R/W: Interrupt status register */ +#define ICP_MULTI_INT_ADC_RDY BIT(0) /* A/D conversion ready interrupt */ +#define ICP_MULTI_INT_DAC_RDY BIT(1) /* D/A conversion ready interrupt */ +#define ICP_MULTI_INT_DOUT_ERR BIT(2) /* Digital output error interrupt */ +#define ICP_MULTI_INT_DIN_STAT BIT(3) /* Digital input status change int. */ +#define ICP_MULTI_INT_CIE0 BIT(4) /* Counter 0 overrun interrupt */ +#define ICP_MULTI_INT_CIE1 BIT(5) /* Counter 1 overrun interrupt */ +#define ICP_MULTI_INT_CIE2 BIT(6) /* Counter 2 overrun interrupt */ +#define ICP_MULTI_INT_CIE3 BIT(7) /* Counter 3 overrun interrupt */ +#define ICP_MULTI_INT_MASK 0xff /* All interrupts */ #define ICP_MULTI_CNTR0 0x10 /* R/W: Counter 0 */ #define ICP_MULTI_CNTR1 0x12 /* R/W: counter 1 */ #define ICP_MULTI_CNTR2 0x14 /* R/W: Counter 2 */ #define ICP_MULTI_CNTR3 0x16 /* R/W: Counter 3 */ -/* Define bits from ADC command/status register */ -#define ADC_ST 0x0001 /* Start ADC */ -#define ADC_BSY 0x0001 /* ADC busy */ -#define ADC_BI 0x0010 /* Bipolar input range 1 = bipolar */ -#define ADC_RA 0x0020 /* Input range 0 = 5V, 1 = 10V */ -#define ADC_DI 0x0040 /* Differential input mode 1 = differential */ - -/* Define bits from DAC command/status register */ -#define DAC_ST 0x0001 /* Start DAC */ -#define DAC_BSY 0x0001 /* DAC busy */ -#define DAC_BI 0x0010 /* Bipolar input range 1 = bipolar */ -#define DAC_RA 0x0020 /* Input range 0 = 5V, 1 = 10V */ - -/* Define bits from interrupt enable/status registers */ -#define ADC_READY 0x0001 /* A/d conversion ready interrupt */ -#define DAC_READY 0x0002 /* D/a conversion ready interrupt */ -#define DOUT_ERROR 0x0004 /* Digital output error interrupt */ -#define DIN_STATUS 0x0008 /* Digital input status change interrupt */ -#define CIE0 0x0010 /* Counter 0 overrun interrupt */ -#define CIE1 0x0020 /* Counter 1 overrun interrupt */ -#define CIE2 0x0040 /* Counter 2 overrun interrupt */ -#define CIE3 0x0080 /* Counter 3 overrun interrupt */ - -/* Useful definitions */ -#define Status_IRQ 0x00ff /* All interrupts */ - -/* Define analogue range */ -static const struct comedi_lrange range_analog = { +/* analog input and output have the same range options */ +static const struct comedi_lrange icp_multi_ranges = { 4, { UNI_RANGE(5), UNI_RANGE(10), @@ -99,71 +94,6 @@ static const struct comedi_lrange range_analog = { static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 }; -/* -============================================================================== - Data & Structure declarations -============================================================================== -*/ - -struct icp_multi_private { - unsigned int AdcCmdStatus; /* ADC Command/Status register */ - unsigned int DacCmdStatus; /* DAC Command/Status register */ - unsigned int IntEnable; /* Interrupt Enable register */ - unsigned int IntStatus; /* Interrupt Status register */ - unsigned int act_chanlist[32]; /* list of scanned channel */ - unsigned char act_chanlist_len; /* len of scanlist */ - unsigned char act_chanlist_pos; /* actual position in MUX list */ - unsigned int *ai_chanlist; /* actaul chanlist */ - unsigned int do_data; /* Remember digital output data */ -}; - -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan) -{ - struct icp_multi_private *devpriv = dev->private; - unsigned int i, range, chanprog; - unsigned int diff; - - devpriv->act_chanlist_len = n_chan; - devpriv->act_chanlist_pos = 0; - - for (i = 0; i < n_chan; i++) { - /* Get channel */ - chanprog = CR_CHAN(chanlist[i]); - - /* Determine if it is a differential channel (Bit 15 = 1) */ - if (CR_AREF(chanlist[i]) == AREF_DIFF) { - diff = 1; - chanprog &= 0x0007; - } else { - diff = 0; - chanprog &= 0x000f; - } - - /* Clear channel, range and input mode bits - * in A/D command/status register */ - devpriv->AdcCmdStatus &= 0xf00f; - - /* Set channel number and differential mode status bit */ - if (diff) { - /* Set channel number, bits 9-11 & mode, bit 6 */ - devpriv->AdcCmdStatus |= (chanprog << 9); - devpriv->AdcCmdStatus |= ADC_DI; - } else - /* Set channel number, bits 8-11 */ - devpriv->AdcCmdStatus |= (chanprog << 8); - - /* Get range for current channel */ - range = range_codes_analog[CR_RANGE(chanlist[i])]; - /* Set range. bits 4-5 */ - devpriv->AdcCmdStatus |= range; - - /* Output channel, range, mode to ICP Multi */ - writew(devpriv->AdcCmdStatus, dev->mmio + ICP_MULTI_ADC_CSR); - } -} - static int icp_multi_ai_eoc(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -172,36 +102,37 @@ static int icp_multi_ai_eoc(struct comedi_device *dev, unsigned int status; status = readw(dev->mmio + ICP_MULTI_ADC_CSR); - if ((status & ADC_BSY) == 0) + if ((status & ICP_MULTI_ADC_CSR_BSY) == 0) return 0; return -EBUSY; } -static int icp_multi_insn_read_ai(struct comedi_device *dev, +static int icp_multi_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - struct icp_multi_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int aref = CR_AREF(insn->chanspec); + unsigned int adc_csr; int ret = 0; int n; - /* Disable A/D conversion ready interrupt */ - devpriv->IntEnable &= ~ADC_READY; - writew(devpriv->IntEnable, dev->mmio + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= ADC_READY; - writew(devpriv->IntStatus, dev->mmio + ICP_MULTI_INT_STAT); - - /* Set up appropriate channel, mode and range data, for specified ch */ - setup_channel_list(dev, s, &insn->chanspec, 1); + /* Set mode and range data for specified channel */ + if (aref == AREF_DIFF) { + adc_csr = ICP_MULTI_ADC_CSR_DI_CHAN(chan) | + ICP_MULTI_ADC_CSR_DI; + } else { + adc_csr = ICP_MULTI_ADC_CSR_SE_CHAN(chan); + } + adc_csr |= range_codes_analog[range]; + writew(adc_csr, dev->mmio + ICP_MULTI_ADC_CSR); for (n = 0; n < insn->n; n++) { /* Set start ADC bit */ - devpriv->AdcCmdStatus |= ADC_ST; - writew(devpriv->AdcCmdStatus, dev->mmio + ICP_MULTI_ADC_CSR); - devpriv->AdcCmdStatus &= ~ADC_ST; + writew(adc_csr | ICP_MULTI_ADC_CSR_ST, + dev->mmio + ICP_MULTI_ADC_CSR); udelay(1); @@ -213,26 +144,18 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, data[n] = (readw(dev->mmio + ICP_MULTI_AI) >> 4) & 0x0fff; } - /* Disable interrupt */ - devpriv->IntEnable &= ~ADC_READY; - writew(devpriv->IntEnable, dev->mmio + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= ADC_READY; - writew(devpriv->IntStatus, dev->mmio + ICP_MULTI_INT_STAT); - return ret ? ret : n; } -static int icp_multi_ao_eoc(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned long context) +static int icp_multi_ao_ready(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned int status; status = readw(dev->mmio + ICP_MULTI_DAC_CSR); - if ((status & DAC_BSY) == 0) + if ((status & ICP_MULTI_DAC_CSR_BSY) == 0) return 0; return -EBUSY; } @@ -242,57 +165,30 @@ static int icp_multi_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - struct icp_multi_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); + unsigned int dac_csr; int i; - /* Disable D/A conversion ready interrupt */ - devpriv->IntEnable &= ~DAC_READY; - writew(devpriv->IntEnable, dev->mmio + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= DAC_READY; - writew(devpriv->IntStatus, dev->mmio + ICP_MULTI_INT_STAT); - - /* Set up range and channel data */ - /* Bit 4 = 1 : Bipolar */ - /* Bit 5 = 0 : 5V */ - /* Bit 5 = 1 : 10V */ - /* Bits 8-9 : Channel number */ - devpriv->DacCmdStatus &= 0xfccf; - devpriv->DacCmdStatus |= range_codes_analog[range]; - devpriv->DacCmdStatus |= (chan << 8); - - writew(devpriv->DacCmdStatus, dev->mmio + ICP_MULTI_DAC_CSR); + /* Select channel and range */ + dac_csr = ICP_MULTI_DAC_CSR_CHAN(chan); + dac_csr |= range_codes_analog[range]; + writew(dac_csr, dev->mmio + ICP_MULTI_DAC_CSR); for (i = 0; i < insn->n; i++) { unsigned int val = data[i]; int ret; - /* Wait for analogue output data register to be - * ready for new data, or get fed up waiting */ - ret = comedi_timeout(dev, s, insn, icp_multi_ao_eoc, 0); - if (ret) { - /* Disable interrupt */ - devpriv->IntEnable &= ~DAC_READY; - writew(devpriv->IntEnable, - dev->mmio + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= DAC_READY; - writew(devpriv->IntStatus, - dev->mmio + ICP_MULTI_INT_STAT); - + /* Wait for analog output to be ready for new data */ + ret = comedi_timeout(dev, s, insn, icp_multi_ao_ready, 0); + if (ret) return ret; - } writew(val, dev->mmio + ICP_MULTI_AO); - /* Set DAC_ST bit to write the data to selected channel */ - devpriv->DacCmdStatus |= DAC_ST; - writew(devpriv->DacCmdStatus, dev->mmio + ICP_MULTI_DAC_CSR); - devpriv->DacCmdStatus &= ~DAC_ST; + /* Set start conversion bit to write data to channel */ + writew(dac_csr | ICP_MULTI_DAC_CSR_ST, + dev->mmio + ICP_MULTI_DAC_CSR); s->readback[chan] = val; } @@ -300,7 +196,7 @@ static int icp_multi_ao_insn_write(struct comedi_device *dev, return insn->n; } -static int icp_multi_insn_bits_di(struct comedi_device *dev, +static int icp_multi_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -310,7 +206,7 @@ static int icp_multi_insn_bits_di(struct comedi_device *dev, return insn->n; } -static int icp_multi_insn_bits_do(struct comedi_device *dev, +static int icp_multi_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -323,116 +219,27 @@ static int icp_multi_insn_bits_do(struct comedi_device *dev, return insn->n; } -static int icp_multi_insn_read_ctr(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - return 0; -} - -static int icp_multi_insn_write_ctr(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - return 0; -} - -static irqreturn_t interrupt_service_icp_multi(int irq, void *d) -{ - struct comedi_device *dev = d; - int int_no; - - /* Is this interrupt from our board? */ - int_no = readw(dev->mmio + ICP_MULTI_INT_STAT) & Status_IRQ; - if (!int_no) - /* No, exit */ - return IRQ_NONE; - - /* Determine which interrupt is active & handle it */ - switch (int_no) { - case ADC_READY: - break; - case DAC_READY: - break; - case DOUT_ERROR: - break; - case DIN_STATUS: - break; - case CIE0: - break; - case CIE1: - break; - case CIE2: - break; - case CIE3: - break; - default: - break; - } - - return IRQ_HANDLED; -} - -#if 0 -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan) -{ - unsigned int i; - - /* Check that we at least have one channel to check */ - if (n_chan < 1) { - dev_err(dev->class_dev, "range/channel list is empty!\n"); - return 0; - } - /* Check all channels */ - for (i = 0; i < n_chan; i++) { - /* Check that channel number is < maximum */ - if (CR_AREF(chanlist[i]) == AREF_DIFF) { - if (CR_CHAN(chanlist[i]) > (s->nchan / 2)) { - dev_err(dev->class_dev, - "Incorrect differential ai ch-nr\n"); - return 0; - } - } else { - if (CR_CHAN(chanlist[i]) > s->n_chan) { - dev_err(dev->class_dev, - "Incorrect ai channel number\n"); - return 0; - } - } - } - return 1; -} -#endif - static int icp_multi_reset(struct comedi_device *dev) { - struct icp_multi_private *devpriv = dev->private; - unsigned int i; + int i; - /* Clear INT enables and requests */ + /* Disable all interrupts and clear any requests */ writew(0, dev->mmio + ICP_MULTI_INT_EN); - writew(0x00ff, dev->mmio + ICP_MULTI_INT_STAT); + writew(ICP_MULTI_INT_MASK, dev->mmio + ICP_MULTI_INT_STAT); - /* Set DACs to 0..5V range and 0V output */ + /* Reset the analog output channels to 0V */ for (i = 0; i < 4; i++) { - devpriv->DacCmdStatus &= 0xfcce; + unsigned int dac_csr = ICP_MULTI_DAC_CSR_CHAN(i); - /* Set channel number */ - devpriv->DacCmdStatus |= (i << 8); + /* Select channel and 0..5V range */ + writew(dac_csr, dev->mmio + ICP_MULTI_DAC_CSR); - /* Output 0V */ + /* Output 0V */ writew(0, dev->mmio + ICP_MULTI_AO); - /* Set start conversion bit */ - devpriv->DacCmdStatus |= DAC_ST; - - /* Output to command / status register */ - writew(devpriv->DacCmdStatus, dev->mmio + ICP_MULTI_DAC_CSR); - - /* Delay to allow DAC time to recover */ + /* Set start conversion bit to write data to channel */ + writew(dac_csr | ICP_MULTI_DAC_CSR_ST, + dev->mmio + ICP_MULTI_DAC_CSR); udelay(1); } @@ -446,14 +253,9 @@ static int icp_multi_auto_attach(struct comedi_device *dev, unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct icp_multi_private *devpriv; struct comedi_subdevice *s; int ret; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - ret = comedi_pci_enable(dev); if (ret) return ret; @@ -462,85 +264,60 @@ static int icp_multi_auto_attach(struct comedi_device *dev, if (!dev->mmio) return -ENOMEM; - ret = comedi_alloc_subdevices(dev, 5); + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; icp_multi_reset(dev); - if (pcidev->irq) { - ret = request_irq(pcidev->irq, interrupt_service_icp_multi, - IRQF_SHARED, dev->board_name, dev); - if (ret == 0) - dev->irq = pcidev->irq; - } - + /* Analog Input subdevice */ s = &dev->subdevices[0]; - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; - s->n_chan = 16; - s->maxdata = 0x0fff; - s->len_chanlist = 16; - s->range_table = &range_analog; - s->insn_read = icp_multi_insn_read_ai; - + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; + s->n_chan = 16; + s->maxdata = 0x0fff; + s->range_table = &icp_multi_ranges; + s->insn_read = icp_multi_ai_insn_read; + + /* Analog Output subdevice */ s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 4; - s->maxdata = 0x0fff; - s->len_chanlist = 4; - s->range_table = &range_analog; - s->insn_write = icp_multi_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 4; + s->maxdata = 0x0fff; + s->range_table = &icp_multi_ranges; + s->insn_write = icp_multi_ao_insn_write; ret = comedi_alloc_subdev_readback(s); if (ret) return ret; + /* Digital Input subdevice */ s = &dev->subdevices[2]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 16; - s->range_table = &range_digital; - s->insn_bits = icp_multi_insn_bits_di; - + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = icp_multi_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[3]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->len_chanlist = 8; - s->range_table = &range_digital; - s->insn_bits = icp_multi_insn_bits_do; - - s = &dev->subdevices[4]; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 0xffff; - s->len_chanlist = 4; - s->state = 0; - s->insn_read = icp_multi_insn_read_ctr; - s->insn_write = icp_multi_insn_write_ctr; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = icp_multi_do_insn_bits; return 0; } -static void icp_multi_detach(struct comedi_device *dev) -{ - if (dev->mmio) - icp_multi_reset(dev); - comedi_pci_detach(dev); -} - static struct comedi_driver icp_multi_driver = { .driver_name = "icp_multi", .module = THIS_MODULE, .auto_attach = icp_multi_auto_attach, - .detach = icp_multi_detach, + .detach = comedi_pci_detach, }; static int icp_multi_pci_probe(struct pci_dev *dev, @@ -564,5 +341,5 @@ static struct pci_driver icp_multi_pci_driver = { module_comedi_pci_driver(icp_multi_driver, icp_multi_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Inova ICP_MULTI board"); MODULE_LICENSE("GPL"); |