aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/comedi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi')
-rw-r--r--drivers/staging/comedi/Kconfig53
-rw-r--r--drivers/staging/comedi/Makefile2
-rw-r--r--drivers/staging/comedi/TODO1
-rw-r--r--drivers/staging/comedi/comedi_buf.c194
-rw-r--r--drivers/staging/comedi/comedi_fops.c773
-rw-r--r--drivers/staging/comedi/comedi_internal.h10
-rw-r--r--drivers/staging/comedi/comedidev.h117
-rw-r--r--drivers/staging/comedi/drivers.c70
-rw-r--r--drivers/staging/comedi/drivers/8253.h109
-rw-r--r--drivers/staging/comedi/drivers/8255.c11
-rw-r--r--drivers/staging/comedi/drivers/8255.h4
-rw-r--r--drivers/staging/comedi/drivers/8255_pci.c54
-rw-r--r--drivers/staging/comedi/drivers/Makefile4
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.h10
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c597
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c1187
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c867
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c279
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c123
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c30
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_035.c16
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1032.c13
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1500.c28
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1516.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1564.c182
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_16xx.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2032.c28
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2200.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3120.c30
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3200.c38
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3501.c8
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3xxx.c112
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c24
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7x3x.c5
-rw-r--r--drivers/staging/comedi/drivers/adl_pci8164.c2
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c439
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c604
-rw-r--r--drivers/staging/comedi/drivers/adq12b.c60
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c683
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c4
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1724.c6
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c12
-rw-r--r--drivers/staging/comedi/drivers/aio_aio12_8.c44
-rw-r--r--drivers/staging/comedi/drivers/aio_iiro_16.c2
-rw-r--r--drivers/staging/comedi/drivers/amcc_s5933.h8
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_common.c60
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_pci.c2
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236.c44
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc263.c2
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c404
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c497
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci263.c4
-rw-r--r--drivers/staging/comedi/drivers/c6xdigio.c535
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c151
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c280
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c473
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c4
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c69
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c6
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c5
-rw-r--r--drivers/staging/comedi/drivers/comedi_fc.c113
-rw-r--r--drivers/staging/comedi/drivers/comedi_fc.h84
-rw-r--r--drivers/staging/comedi/drivers/comedi_parport.c5
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c44
-rw-r--r--drivers/staging/comedi/drivers/contec_pci_dio.c4
-rw-r--r--drivers/staging/comedi/drivers/dac02.c172
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c87
-rw-r--r--drivers/staging/comedi/drivers/das08.c110
-rw-r--r--drivers/staging/comedi/drivers/das08.h4
-rw-r--r--drivers/staging/comedi/drivers/das08_pci.c2
-rw-r--r--drivers/staging/comedi/drivers/das16.c112
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c251
-rw-r--r--drivers/staging/comedi/drivers/das1800.c337
-rw-r--r--drivers/staging/comedi/drivers/das6402.c685
-rw-r--r--drivers/staging/comedi/drivers/das800.c154
-rw-r--r--drivers/staging/comedi/drivers/dmm32at.c257
-rw-r--r--drivers/staging/comedi/drivers/dt2801.c111
-rw-r--r--drivers/staging/comedi/drivers/dt2811.c166
-rw-r--r--drivers/staging/comedi/drivers/dt2814.c106
-rw-r--r--drivers/staging/comedi/drivers/dt2815.c46
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c289
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c93
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c1
-rw-r--r--drivers/staging/comedi/drivers/dyna_pci10xx.c54
-rw-r--r--drivers/staging/comedi/drivers/fl512.c228
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c1193
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c124
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c21
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c893
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.h6
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c211
-rw-r--r--drivers/staging/comedi/drivers/me4000.c155
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c38
-rw-r--r--drivers/staging/comedi/drivers/mf6x4.c351
-rw-r--r--drivers/staging/comedi/drivers/mite.c192
-rw-r--r--drivers/staging/comedi/drivers/mite.h24
-rw-r--r--drivers/staging/comedi/drivers/mpc624.c47
-rw-r--r--drivers/staging/comedi/drivers/multiq3.c38
-rw-r--r--drivers/staging/comedi/drivers/ni_6527.c7
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c13
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c721
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c5
-rw-r--r--drivers/staging/comedi/drivers/ni_at_a2150.c255
-rw-r--r--drivers/staging/comedi/drivers/ni_at_ao.c8
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio.c15
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio16d.c154
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c58
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c4
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c222
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_isadma.c7
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_pci.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c841
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c223
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c75
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.c315
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.h217
-rw-r--r--drivers/staging/comedi/drivers/ni_tio_internal.h431
-rw-r--r--drivers/staging/comedi/drivers/ni_tiocmd.c130
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c61
-rw-r--r--drivers/staging/comedi/drivers/pcl726.c5
-rw-r--r--drivers/staging/comedi/drivers/pcl730.c36
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c1800
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c1191
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c1733
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c12
-rw-r--r--drivers/staging/comedi/drivers/pcmad.c21
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c1511
-rw-r--r--drivers/staging/comedi/drivers/pcmuio.c460
-rw-r--r--drivers/staging/comedi/drivers/plx9080.h21
-rw-r--r--drivers/staging/comedi/drivers/poc.c157
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c25
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c135
-rw-r--r--drivers/staging/comedi/drivers/rti800.c29
-rw-r--r--drivers/staging/comedi/drivers/rti802.c127
-rw-r--r--drivers/staging/comedi/drivers/s526.c34
-rw-r--r--drivers/staging/comedi/drivers/s626.c287
-rw-r--r--drivers/staging/comedi/drivers/skel.c74
-rw-r--r--drivers/staging/comedi/drivers/ssv_dnp.c3
-rw-r--r--drivers/staging/comedi/drivers/unioxx5.c68
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c64
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c97
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c55
-rw-r--r--drivers/staging/comedi/kcomedilib/Makefile2
-rw-r--r--drivers/staging/comedi/kcomedilib/kcomedilib_main.c77
-rw-r--r--drivers/staging/comedi/proc.c54
-rw-r--r--drivers/staging/comedi/range.c46
147 files changed, 12135 insertions, 15948 deletions
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index bfa27e7fc01..a2f6957e7ee 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -160,16 +160,18 @@ config COMEDI_PCL730
Enable support for various simple ISA or PC/104 Digital I/O boards.
These boards all use 8-bit I/O ports.
- Advantech PCL-730 isolated - 16 in/16 out ttl - 16 in/16 out
- ICP ISO-730 isolated - 16 in/16 out ttl - 16 in/16 out
- ADlink ACL-7130 isolated - 16 in/16 out ttl - 16 in/16 out
- Advantech PCM-3730 isolated - 8 in/8 out ttl - 16 in/16 out
- Advantech PCL-725 isolated - 8 in/8 out
- ICP P8R8-DIO isolated - 8 in/8 out
- ADlink ACL-7225b isolated - 16 in/16 out
- ICP P16R16-DIO isolated - 16 in/16 out
- Advantech PCL-733 isolated - 32 in
- Advantech PCL-734 isolated - 32 out
+ Advantech PCL-730 iso - 16 in/16 out ttl - 16 in/16 out
+ ICP ISO-730 iso - 16 in/16 out ttl - 16 in/16 out
+ ADlink ACL-7130 iso - 16 in/16 out ttl - 16 in/16 out
+ Advantech PCM-3730 iso - 8 in/8 out ttl - 16 in/16 out
+ Advantech PCL-725 iso - 8 in/8 out
+ ICP P8R8-DIO iso - 8 in/8 out
+ ADlink ACL-7225b iso - 16 in/16 out
+ ICP P16R16-DIO iso - 16 in/16 out
+ Advantech PCL-733 iso - 32 in
+ Advantech PCL-734 iso - 32 out
+ Diamond Systems OPMM-1616-XT iso - 16 in/16 out
+ Diamond Systems PEARL-MM-P iso - 16 out
To compile this driver as a module, choose M here: the module will be
called pcl730.
@@ -177,6 +179,7 @@ config COMEDI_PCL730
config COMEDI_PCL812
tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216"
depends on VIRT_TO_BUS && ISA_DMA_API
+ select COMEDI_FC
---help---
Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink
ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA,
@@ -188,6 +191,7 @@ config COMEDI_PCL812
config COMEDI_PCL816
tristate "Advantech PCL-814 and PCL-816 ISA card support"
depends on VIRT_TO_BUS && ISA_DMA_API
+ select COMEDI_FC
---help---
Enable support for Advantech PCL-814 and PCL-816 ISA cards
@@ -197,6 +201,7 @@ config COMEDI_PCL816
config COMEDI_PCL818
tristate "Advantech PCL-718 and PCL-818 ISA card support"
depends on VIRT_TO_BUS && ISA_DMA_API
+ select COMEDI_FC
---help---
Enable support for Advantech PCL-818 ISA cards
PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718
@@ -257,6 +262,14 @@ config COMEDI_RTI802
To compile this driver as a module, choose M here: the module will be
called rti802.
+config COMEDI_DAC02
+ tristate "Keithley Metrabyte DAC02 compatible ISA card support"
+ ---help---
+ Enable support for Keithley Metrabyte DAC02 compatible ISA cards.
+
+ To compile this driver as a module, choose M here: the module will be
+ called dac02.
+
config COMEDI_DAS16M1
tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support"
select COMEDI_8255
@@ -559,15 +572,6 @@ config COMEDI_MULTIQ3
To compile this driver as a module, choose M here: the module will be
called multiq3.
-config COMEDI_POC
- tristate "Generic driver for very simple devices"
- ---help---
- Enable generic support for very simple / POC (Piece of Crap) boards,
- Keithley Metrabyte DAC-02 (dac02).
-
- To compile this driver as a module, choose M here: the module will be
- called poc.
-
config COMEDI_S526
tristate "Sensoray s526 support"
---help---
@@ -647,6 +651,7 @@ config COMEDI_ADDI_APCI_1516
config COMEDI_ADDI_APCI_1564
tristate "ADDI-DATA APCI_1564 support"
+ select COMEDI_ADDI_WATCHDOG
---help---
Enable support for ADDI-DATA APCI_1564 cards
@@ -753,6 +758,7 @@ config COMEDI_ADL_PCI9118
config COMEDI_ADV_PCI1710
tristate "Advantech PCI-171x, PCI-1720 and PCI-1731 support"
+ select COMEDI_FC
---help---
Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711,
PCI-1713, PCI-1720 and PCI-1731
@@ -856,6 +862,7 @@ config COMEDI_DAS08_PCI
config COMEDI_DT3000
tristate "Data Translation DT3000 series support"
+ select COMEDI_FC
---help---
Enable support for Data Translation DT3000 series
DT3001, DT3001-PGL, DT3002, DT3003, DT3003-PGL, DT3004, DT3005 and
@@ -884,6 +891,12 @@ config COMEDI_GSC_HPDI
To compile this driver as a module, choose M here: the module will be
called gsc_hpdi.
+config COMEDI_MF6X4
+ tristate "Humusoft MF634 and MF624 DAQ Card support"
+ ---help---
+ This driver supports both Humusoft MF634 and MF624 Data acquisition
+ cards. The legacy Humusoft MF614 card is not supported.
+
config COMEDI_ICP_MULTI
tristate "Inova ICP_MULTI support"
---help---
@@ -1095,6 +1108,7 @@ config COMEDI_S626
config COMEDI_MITE
depends on HAS_DMA
+ select COMEDI_FC
tristate
config COMEDI_NI_TIOCMD
@@ -1173,6 +1187,7 @@ config COMEDI_NI_MIO_CS
config COMEDI_QUATECH_DAQP_CS
tristate "Quatech DAQP PCMCIA data capture card support"
+ select COMEDI_FC
---help---
Enable support for the Quatech DAQP PCMCIA data capture cards
DAQP-208 and DAQP-308
diff --git a/drivers/staging/comedi/Makefile b/drivers/staging/comedi/Makefile
index e6dfc98f8c8..fae2d909000 100644
--- a/drivers/staging/comedi/Makefile
+++ b/drivers/staging/comedi/Makefile
@@ -1,3 +1,5 @@
+ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG
+
comedi-y := comedi_fops.o range.o drivers.o \
comedi_buf.o
comedi-$(CONFIG_COMEDI_PCI_DRIVERS) += comedi_pci.o
diff --git a/drivers/staging/comedi/TODO b/drivers/staging/comedi/TODO
index fa8da9aada3..b68fbdb5eeb 100644
--- a/drivers/staging/comedi/TODO
+++ b/drivers/staging/comedi/TODO
@@ -3,7 +3,6 @@ TODO:
- Lindent
- remove all wrappers
- audit userspace interface
- - reserve major number
- cleanup the individual comedi drivers as well
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c
index 4e26bd7fc84..df4a9c4bca3 100644
--- a/drivers/staging/comedi/comedi_buf.c
+++ b/drivers/staging/comedi/comedi_buf.c
@@ -16,6 +16,7 @@
*/
#include <linux/vmalloc.h>
+#include <linux/slab.h>
#include "comedidev.h"
#include "comedi_internal.h"
@@ -26,31 +27,21 @@
#define COMEDI_PAGE_PROTECTION PAGE_KERNEL
#endif
-static void __comedi_buf_free(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned n_pages)
+static void comedi_buf_map_kref_release(struct kref *kref)
{
- struct comedi_async *async = s->async;
+ struct comedi_buf_map *bm =
+ container_of(kref, struct comedi_buf_map, refcount);
struct comedi_buf_page *buf;
- unsigned i;
+ unsigned int i;
- if (async->prealloc_buf) {
- vunmap(async->prealloc_buf);
- async->prealloc_buf = NULL;
- async->prealloc_bufsz = 0;
- }
-
- if (!async->buf_page_list)
- return;
-
- for (i = 0; i < n_pages; ++i) {
- buf = &async->buf_page_list[i];
- if (buf->virt_addr) {
+ if (bm->page_list) {
+ for (i = 0; i < bm->n_pages; i++) {
+ buf = &bm->page_list[i];
clear_bit(PG_reserved,
&(virt_to_page(buf->virt_addr)->flags));
- if (s->async_dma_dir != DMA_NONE) {
+ if (bm->dma_dir != DMA_NONE) {
#ifdef CONFIG_HAS_DMA
- dma_free_coherent(dev->hw_dev,
+ dma_free_coherent(bm->dma_hw_dev,
PAGE_SIZE,
buf->virt_addr,
buf->dma_addr);
@@ -59,10 +50,31 @@ static void __comedi_buf_free(struct comedi_device *dev,
free_page((unsigned long)buf->virt_addr);
}
}
+ vfree(bm->page_list);
}
- vfree(async->buf_page_list);
- async->buf_page_list = NULL;
- async->n_buf_pages = 0;
+ if (bm->dma_dir != DMA_NONE)
+ put_device(bm->dma_hw_dev);
+ kfree(bm);
+}
+
+static void __comedi_buf_free(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct comedi_async *async = s->async;
+ struct comedi_buf_map *bm;
+ unsigned long flags;
+
+ if (async->prealloc_buf) {
+ vunmap(async->prealloc_buf);
+ async->prealloc_buf = NULL;
+ async->prealloc_bufsz = 0;
+ }
+
+ spin_lock_irqsave(&s->spin_lock, flags);
+ bm = async->buf_map;
+ async->buf_map = NULL;
+ spin_unlock_irqrestore(&s->spin_lock, flags);
+ comedi_buf_map_put(bm);
}
static void __comedi_buf_alloc(struct comedi_device *dev,
@@ -71,7 +83,9 @@ static void __comedi_buf_alloc(struct comedi_device *dev,
{
struct comedi_async *async = s->async;
struct page **pages = NULL;
+ struct comedi_buf_map *bm;
struct comedi_buf_page *buf;
+ unsigned long flags;
unsigned i;
if (!IS_ENABLED(CONFIG_HAS_DMA) && s->async_dma_dir != DMA_NONE) {
@@ -80,18 +94,31 @@ static void __comedi_buf_alloc(struct comedi_device *dev,
return;
}
- async->buf_page_list = vzalloc(sizeof(*buf) * n_pages);
- if (async->buf_page_list)
+ bm = kzalloc(sizeof(*async->buf_map), GFP_KERNEL);
+ if (!bm)
+ return;
+
+ kref_init(&bm->refcount);
+ spin_lock_irqsave(&s->spin_lock, flags);
+ async->buf_map = bm;
+ spin_unlock_irqrestore(&s->spin_lock, flags);
+ bm->dma_dir = s->async_dma_dir;
+ if (bm->dma_dir != DMA_NONE)
+ /* Need ref to hardware device to free buffer later. */
+ bm->dma_hw_dev = get_device(dev->hw_dev);
+
+ bm->page_list = vzalloc(sizeof(*buf) * n_pages);
+ if (bm->page_list)
pages = vmalloc(sizeof(struct page *) * n_pages);
if (!pages)
return;
for (i = 0; i < n_pages; i++) {
- buf = &async->buf_page_list[i];
- if (s->async_dma_dir != DMA_NONE)
+ buf = &bm->page_list[i];
+ if (bm->dma_dir != DMA_NONE)
#ifdef CONFIG_HAS_DMA
- buf->virt_addr = dma_alloc_coherent(dev->hw_dev,
+ buf->virt_addr = dma_alloc_coherent(bm->dma_hw_dev,
PAGE_SIZE,
&buf->dma_addr,
GFP_KERNEL |
@@ -108,6 +135,9 @@ static void __comedi_buf_alloc(struct comedi_device *dev,
pages[i] = virt_to_page(buf->virt_addr);
}
+ spin_lock_irqsave(&s->spin_lock, flags);
+ bm->n_pages = i;
+ spin_unlock_irqrestore(&s->spin_lock, flags);
/* vmap the prealloc_buf if all the pages were allocated */
if (i == n_pages)
@@ -117,6 +147,49 @@ static void __comedi_buf_alloc(struct comedi_device *dev,
vfree(pages);
}
+void comedi_buf_map_get(struct comedi_buf_map *bm)
+{
+ if (bm)
+ kref_get(&bm->refcount);
+}
+
+int comedi_buf_map_put(struct comedi_buf_map *bm)
+{
+ if (bm)
+ return kref_put(&bm->refcount, comedi_buf_map_kref_release);
+ return 1;
+}
+
+/* returns s->async->buf_map and increments its kref refcount */
+struct comedi_buf_map *
+comedi_buf_map_from_subdev_get(struct comedi_subdevice *s)
+{
+ struct comedi_async *async = s->async;
+ struct comedi_buf_map *bm = NULL;
+ unsigned long flags;
+
+ if (!async)
+ return NULL;
+
+ spin_lock_irqsave(&s->spin_lock, flags);
+ bm = async->buf_map;
+ /* only want it if buffer pages allocated */
+ if (bm && bm->n_pages)
+ comedi_buf_map_get(bm);
+ else
+ bm = NULL;
+ spin_unlock_irqrestore(&s->spin_lock, flags);
+
+ return bm;
+}
+
+bool comedi_buf_is_mmapped(struct comedi_subdevice *s)
+{
+ struct comedi_buf_map *bm = s->async->buf_map;
+
+ return bm && (atomic_read(&bm->refcount.refcount) > 1);
+}
+
int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned long new_size)
{
@@ -130,7 +203,7 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
/* deallocate old buffer */
- __comedi_buf_free(dev, s, async->n_buf_pages);
+ __comedi_buf_free(dev, s);
/* allocate new buffer */
if (new_size) {
@@ -140,18 +213,19 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
if (!async->prealloc_buf) {
/* allocation failed */
- __comedi_buf_free(dev, s, n_pages);
+ __comedi_buf_free(dev, s);
return -ENOMEM;
}
- async->n_buf_pages = n_pages;
}
async->prealloc_bufsz = new_size;
return 0;
}
-void comedi_buf_reset(struct comedi_async *async)
+void comedi_buf_reset(struct comedi_subdevice *s)
{
+ struct comedi_async *async = s->async;
+
async->buf_write_alloc_count = 0;
async->buf_write_count = 0;
async->buf_read_alloc_count = 0;
@@ -169,18 +243,20 @@ void comedi_buf_reset(struct comedi_async *async)
async->events = 0;
}
-static unsigned int comedi_buf_write_n_available(struct comedi_async *async)
+static unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s)
{
+ struct comedi_async *async = s->async;
unsigned int free_end = async->buf_read_count + async->prealloc_bufsz;
return free_end - async->buf_write_alloc_count;
}
-static unsigned int __comedi_buf_write_alloc(struct comedi_async *async,
+static unsigned int __comedi_buf_write_alloc(struct comedi_subdevice *s,
unsigned int nbytes,
int strict)
{
- unsigned int available = comedi_buf_write_n_available(async);
+ struct comedi_async *async = s->async;
+ unsigned int available = comedi_buf_write_n_available(s);
if (nbytes > available)
nbytes = strict ? 0 : available;
@@ -197,10 +273,10 @@ static unsigned int __comedi_buf_write_alloc(struct comedi_async *async,
}
/* allocates chunk for the writer from free buffer space */
-unsigned int comedi_buf_write_alloc(struct comedi_async *async,
+unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s,
unsigned int nbytes)
{
- return __comedi_buf_write_alloc(async, nbytes, 0);
+ return __comedi_buf_write_alloc(s, nbytes, 0);
}
EXPORT_SYMBOL_GPL(comedi_buf_write_alloc);
@@ -208,10 +284,10 @@ EXPORT_SYMBOL_GPL(comedi_buf_write_alloc);
* munging is applied to data by core as it passes between user
* and kernel space
*/
-static unsigned int comedi_buf_munge(struct comedi_async *async,
+static unsigned int comedi_buf_munge(struct comedi_subdevice *s,
unsigned int num_bytes)
{
- struct comedi_subdevice *s = async->subdevice;
+ struct comedi_async *async = s->async;
unsigned int count = 0;
const unsigned num_sample_bytes = bytes_per_sample(s);
@@ -251,23 +327,26 @@ static unsigned int comedi_buf_munge(struct comedi_async *async,
return count;
}
-unsigned int comedi_buf_write_n_allocated(struct comedi_async *async)
+unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s)
{
+ struct comedi_async *async = s->async;
+
return async->buf_write_alloc_count - async->buf_write_count;
}
/* transfers a chunk from writer to filled buffer space */
-unsigned int comedi_buf_write_free(struct comedi_async *async,
+unsigned int comedi_buf_write_free(struct comedi_subdevice *s,
unsigned int nbytes)
{
- unsigned int allocated = comedi_buf_write_n_allocated(async);
+ struct comedi_async *async = s->async;
+ unsigned int allocated = comedi_buf_write_n_allocated(s);
if (nbytes > allocated)
nbytes = allocated;
async->buf_write_count += nbytes;
async->buf_write_ptr += nbytes;
- comedi_buf_munge(async, async->buf_write_count - async->munge_count);
+ comedi_buf_munge(s, async->buf_write_count - async->munge_count);
if (async->buf_write_ptr >= async->prealloc_bufsz)
async->buf_write_ptr %= async->prealloc_bufsz;
@@ -275,8 +354,9 @@ unsigned int comedi_buf_write_free(struct comedi_async *async,
}
EXPORT_SYMBOL_GPL(comedi_buf_write_free);
-unsigned int comedi_buf_read_n_available(struct comedi_async *async)
+unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s)
{
+ struct comedi_async *async = s->async;
unsigned num_bytes;
if (!async)
@@ -295,9 +375,10 @@ unsigned int comedi_buf_read_n_available(struct comedi_async *async)
EXPORT_SYMBOL_GPL(comedi_buf_read_n_available);
/* allocates a chunk for the reader from filled (and munged) buffer space */
-unsigned int comedi_buf_read_alloc(struct comedi_async *async,
+unsigned int comedi_buf_read_alloc(struct comedi_subdevice *s,
unsigned int nbytes)
{
+ struct comedi_async *async = s->async;
unsigned int available;
available = async->munge_count - async->buf_read_alloc_count;
@@ -322,9 +403,10 @@ static unsigned int comedi_buf_read_n_allocated(struct comedi_async *async)
}
/* transfers control of a chunk from reader to free buffer space */
-unsigned int comedi_buf_read_free(struct comedi_async *async,
+unsigned int comedi_buf_read_free(struct comedi_subdevice *s,
unsigned int nbytes)
{
+ struct comedi_async *async = s->async;
unsigned int allocated;
/*
@@ -344,36 +426,39 @@ unsigned int comedi_buf_read_free(struct comedi_async *async,
}
EXPORT_SYMBOL_GPL(comedi_buf_read_free);
-int comedi_buf_put(struct comedi_async *async, unsigned short x)
+int comedi_buf_put(struct comedi_subdevice *s, unsigned short x)
{
- unsigned int n = __comedi_buf_write_alloc(async, sizeof(short), 1);
+ struct comedi_async *async = s->async;
+ unsigned int n = __comedi_buf_write_alloc(s, sizeof(short), 1);
if (n < sizeof(short)) {
async->events |= COMEDI_CB_ERROR;
return 0;
}
*(unsigned short *)(async->prealloc_buf + async->buf_write_ptr) = x;
- comedi_buf_write_free(async, sizeof(short));
+ comedi_buf_write_free(s, sizeof(short));
return 1;
}
EXPORT_SYMBOL_GPL(comedi_buf_put);
-int comedi_buf_get(struct comedi_async *async, unsigned short *x)
+int comedi_buf_get(struct comedi_subdevice *s, unsigned short *x)
{
- unsigned int n = comedi_buf_read_n_available(async);
+ struct comedi_async *async = s->async;
+ unsigned int n = comedi_buf_read_n_available(s);
if (n < sizeof(short))
return 0;
- comedi_buf_read_alloc(async, sizeof(short));
+ comedi_buf_read_alloc(s, sizeof(short));
*x = *(unsigned short *)(async->prealloc_buf + async->buf_read_ptr);
- comedi_buf_read_free(async, sizeof(short));
+ comedi_buf_read_free(s, sizeof(short));
return 1;
}
EXPORT_SYMBOL_GPL(comedi_buf_get);
-void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset,
+void comedi_buf_memcpy_to(struct comedi_subdevice *s, unsigned int offset,
const void *data, unsigned int num_bytes)
{
+ struct comedi_async *async = s->async;
unsigned int write_ptr = async->buf_write_ptr + offset;
if (write_ptr >= async->prealloc_bufsz)
@@ -397,10 +482,11 @@ void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset,
}
EXPORT_SYMBOL_GPL(comedi_buf_memcpy_to);
-void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset,
+void comedi_buf_memcpy_from(struct comedi_subdevice *s, unsigned int offset,
void *dest, unsigned int nbytes)
{
void *src;
+ struct comedi_async *async = s->async;
unsigned int read_ptr = async->buf_read_ptr + offset;
if (read_ptr >= async->prealloc_bufsz)
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index f3d59e2a115..9d99fb3c18a 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -16,8 +16,6 @@
GNU General Public License for more details.
*/
-#undef DEBUG
-
#include "comedi_compat32.h"
#include <linux/module.h>
@@ -47,15 +45,6 @@
#define COMEDI_NUM_SUBDEVICE_MINORS \
(COMEDI_NUM_MINORS - COMEDI_NUM_BOARD_MINORS)
-#ifdef CONFIG_COMEDI_DEBUG
-int comedi_debug;
-EXPORT_SYMBOL_GPL(comedi_debug);
-module_param(comedi_debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(comedi_debug,
- "enable comedi core and driver debugging if non-zero (default 0)"
- );
-#endif
-
static int comedi_num_legacy_minors;
module_param(comedi_num_legacy_minors, int, S_IRUGO);
MODULE_PARM_DESC(comedi_num_legacy_minors,
@@ -89,11 +78,38 @@ static struct cdev comedi_cdev;
static void comedi_device_init(struct comedi_device *dev)
{
+ kref_init(&dev->refcount);
spin_lock_init(&dev->spinlock);
mutex_init(&dev->mutex);
+ init_rwsem(&dev->attach_lock);
dev->minor = -1;
}
+static void comedi_dev_kref_release(struct kref *kref)
+{
+ struct comedi_device *dev =
+ container_of(kref, struct comedi_device, refcount);
+
+ mutex_destroy(&dev->mutex);
+ put_device(dev->class_dev);
+ kfree(dev);
+}
+
+int comedi_dev_put(struct comedi_device *dev)
+{
+ if (dev)
+ return kref_put(&dev->refcount, comedi_dev_kref_release);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(comedi_dev_put);
+
+static struct comedi_device *comedi_dev_get(struct comedi_device *dev)
+{
+ if (dev)
+ kref_get(&dev->refcount);
+ return dev;
+}
+
static void comedi_device_cleanup(struct comedi_device *dev)
{
struct module *driver_module = NULL;
@@ -104,14 +120,9 @@ static void comedi_device_cleanup(struct comedi_device *dev)
if (dev->attached)
driver_module = dev->driver->module;
comedi_device_detach(dev);
- while (dev->use_count > 0) {
- if (driver_module)
- module_put(driver_module);
- module_put(THIS_MODULE);
- dev->use_count--;
- }
+ if (driver_module && dev->use_count)
+ module_put(driver_module);
mutex_unlock(&dev->mutex);
- mutex_destroy(&dev->mutex);
}
static bool comedi_clear_board_dev(struct comedi_device *dev)
@@ -142,17 +153,17 @@ static struct comedi_device *comedi_clear_board_minor(unsigned minor)
static void comedi_free_board_dev(struct comedi_device *dev)
{
if (dev) {
+ comedi_device_cleanup(dev);
if (dev->class_dev) {
device_destroy(comedi_class,
MKDEV(COMEDI_MAJOR, dev->minor));
}
- comedi_device_cleanup(dev);
- kfree(dev);
+ comedi_dev_put(dev);
}
}
static struct comedi_subdevice
-*comedi_subdevice_from_minor(unsigned minor)
+*comedi_subdevice_from_minor(const struct comedi_device *dev, unsigned minor)
{
struct comedi_subdevice *s;
unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
@@ -160,37 +171,45 @@ static struct comedi_subdevice
BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS);
mutex_lock(&comedi_subdevice_minor_table_lock);
s = comedi_subdevice_minor_table[i];
+ if (s && s->device != dev)
+ s = NULL;
mutex_unlock(&comedi_subdevice_minor_table_lock);
return s;
}
-static struct comedi_device *comedi_dev_from_board_minor(unsigned minor)
+static struct comedi_device *comedi_dev_get_from_board_minor(unsigned minor)
{
struct comedi_device *dev;
BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
mutex_lock(&comedi_board_minor_table_lock);
- dev = comedi_board_minor_table[minor];
+ dev = comedi_dev_get(comedi_board_minor_table[minor]);
mutex_unlock(&comedi_board_minor_table_lock);
return dev;
}
-static struct comedi_device *comedi_dev_from_subdevice_minor(unsigned minor)
+static struct comedi_device *comedi_dev_get_from_subdevice_minor(unsigned minor)
{
+ struct comedi_device *dev;
struct comedi_subdevice *s;
+ unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
- s = comedi_subdevice_from_minor(minor);
- return s ? s->device : NULL;
+ BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS);
+ mutex_lock(&comedi_subdevice_minor_table_lock);
+ s = comedi_subdevice_minor_table[i];
+ dev = comedi_dev_get(s ? s->device : NULL);
+ mutex_unlock(&comedi_subdevice_minor_table_lock);
+ return dev;
}
-struct comedi_device *comedi_dev_from_minor(unsigned minor)
+struct comedi_device *comedi_dev_get_from_minor(unsigned minor)
{
if (minor < COMEDI_NUM_BOARD_MINORS)
- return comedi_dev_from_board_minor(minor);
+ return comedi_dev_get_from_board_minor(minor);
else
- return comedi_dev_from_subdevice_minor(minor);
+ return comedi_dev_get_from_subdevice_minor(minor);
}
-EXPORT_SYMBOL_GPL(comedi_dev_from_minor);
+EXPORT_SYMBOL_GPL(comedi_dev_get_from_minor);
static struct comedi_subdevice *
comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor)
@@ -198,10 +217,8 @@ comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor)
struct comedi_subdevice *s;
if (minor >= COMEDI_NUM_BOARD_MINORS) {
- s = comedi_subdevice_from_minor(minor);
- if (!s || s->device != dev)
- return NULL;
- if (s->subdev_flags & SDF_CMD_READ)
+ s = comedi_subdevice_from_minor(dev, minor);
+ if (s == NULL || (s->subdev_flags & SDF_CMD_READ))
return s;
}
return dev->read_subdev;
@@ -213,30 +230,30 @@ comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor)
struct comedi_subdevice *s;
if (minor >= COMEDI_NUM_BOARD_MINORS) {
- s = comedi_subdevice_from_minor(minor);
- if (!s || s->device != dev)
- return NULL;
- if (s->subdev_flags & SDF_CMD_WRITE)
+ s = comedi_subdevice_from_minor(dev, minor);
+ if (s == NULL || (s->subdev_flags & SDF_CMD_WRITE))
return s;
}
return dev->write_subdev;
}
static int resize_async_buffer(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_async *async, unsigned new_size)
+ struct comedi_subdevice *s, unsigned new_size)
{
+ struct comedi_async *async = s->async;
int retval;
if (new_size > async->max_bufsize)
return -EPERM;
if (s->busy) {
- DPRINTK("subdevice is busy, cannot resize buffer\n");
+ dev_dbg(dev->class_dev,
+ "subdevice is busy, cannot resize buffer\n");
return -EBUSY;
}
- if (async->mmap_count) {
- DPRINTK("subdevice is mmapped, cannot resize buffer\n");
+ if (comedi_buf_is_mmapped(s)) {
+ dev_dbg(dev->class_dev,
+ "subdevice is mmapped, cannot resize buffer\n");
return -EBUSY;
}
@@ -254,8 +271,8 @@ static int resize_async_buffer(struct comedi_device *dev,
return retval;
}
- DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
- dev->minor, s->index, async->prealloc_bufsz);
+ dev_dbg(dev->class_dev, "subd %d buffer resized to %i bytes\n",
+ s->index, async->prealloc_bufsz);
return 0;
}
@@ -269,7 +286,7 @@ static ssize_t max_read_buffer_kb_show(struct device *csdev,
struct comedi_subdevice *s;
unsigned int size = 0;
- dev = comedi_dev_from_minor(minor);
+ dev = comedi_dev_get_from_minor(minor);
if (!dev)
return -ENODEV;
@@ -279,7 +296,8 @@ static ssize_t max_read_buffer_kb_show(struct device *csdev,
size = s->async->max_bufsize / 1024;
mutex_unlock(&dev->mutex);
- return snprintf(buf, PAGE_SIZE, "%i\n", size);
+ comedi_dev_put(dev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", size);
}
static ssize_t max_read_buffer_kb_store(struct device *csdev,
@@ -299,7 +317,7 @@ static ssize_t max_read_buffer_kb_store(struct device *csdev,
return -EINVAL;
size *= 1024;
- dev = comedi_dev_from_minor(minor);
+ dev = comedi_dev_get_from_minor(minor);
if (!dev)
return -ENODEV;
@@ -311,6 +329,7 @@ static ssize_t max_read_buffer_kb_store(struct device *csdev,
err = -EINVAL;
mutex_unlock(&dev->mutex);
+ comedi_dev_put(dev);
return err ? err : count;
}
static DEVICE_ATTR_RW(max_read_buffer_kb);
@@ -323,7 +342,7 @@ static ssize_t read_buffer_kb_show(struct device *csdev,
struct comedi_subdevice *s;
unsigned int size = 0;
- dev = comedi_dev_from_minor(minor);
+ dev = comedi_dev_get_from_minor(minor);
if (!dev)
return -ENODEV;
@@ -333,7 +352,8 @@ static ssize_t read_buffer_kb_show(struct device *csdev,
size = s->async->prealloc_bufsz / 1024;
mutex_unlock(&dev->mutex);
- return snprintf(buf, PAGE_SIZE, "%i\n", size);
+ comedi_dev_put(dev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", size);
}
static ssize_t read_buffer_kb_store(struct device *csdev,
@@ -353,18 +373,19 @@ static ssize_t read_buffer_kb_store(struct device *csdev,
return -EINVAL;
size *= 1024;
- dev = comedi_dev_from_minor(minor);
+ dev = comedi_dev_get_from_minor(minor);
if (!dev)
return -ENODEV;
mutex_lock(&dev->mutex);
s = comedi_read_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
- err = resize_async_buffer(dev, s, s->async, size);
+ err = resize_async_buffer(dev, s, size);
else
err = -EINVAL;
mutex_unlock(&dev->mutex);
+ comedi_dev_put(dev);
return err ? err : count;
}
static DEVICE_ATTR_RW(read_buffer_kb);
@@ -378,7 +399,7 @@ static ssize_t max_write_buffer_kb_show(struct device *csdev,
struct comedi_subdevice *s;
unsigned int size = 0;
- dev = comedi_dev_from_minor(minor);
+ dev = comedi_dev_get_from_minor(minor);
if (!dev)
return -ENODEV;
@@ -388,7 +409,8 @@ static ssize_t max_write_buffer_kb_show(struct device *csdev,
size = s->async->max_bufsize / 1024;
mutex_unlock(&dev->mutex);
- return snprintf(buf, PAGE_SIZE, "%i\n", size);
+ comedi_dev_put(dev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", size);
}
static ssize_t max_write_buffer_kb_store(struct device *csdev,
@@ -408,7 +430,7 @@ static ssize_t max_write_buffer_kb_store(struct device *csdev,
return -EINVAL;
size *= 1024;
- dev = comedi_dev_from_minor(minor);
+ dev = comedi_dev_get_from_minor(minor);
if (!dev)
return -ENODEV;
@@ -420,6 +442,7 @@ static ssize_t max_write_buffer_kb_store(struct device *csdev,
err = -EINVAL;
mutex_unlock(&dev->mutex);
+ comedi_dev_put(dev);
return err ? err : count;
}
static DEVICE_ATTR_RW(max_write_buffer_kb);
@@ -432,7 +455,7 @@ static ssize_t write_buffer_kb_show(struct device *csdev,
struct comedi_subdevice *s;
unsigned int size = 0;
- dev = comedi_dev_from_minor(minor);
+ dev = comedi_dev_get_from_minor(minor);
if (!dev)
return -ENODEV;
@@ -442,7 +465,8 @@ static ssize_t write_buffer_kb_show(struct device *csdev,
size = s->async->prealloc_bufsz / 1024;
mutex_unlock(&dev->mutex);
- return snprintf(buf, PAGE_SIZE, "%i\n", size);
+ comedi_dev_put(dev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", size);
}
static ssize_t write_buffer_kb_store(struct device *csdev,
@@ -462,18 +486,19 @@ static ssize_t write_buffer_kb_store(struct device *csdev,
return -EINVAL;
size *= 1024;
- dev = comedi_dev_from_minor(minor);
+ dev = comedi_dev_get_from_minor(minor);
if (!dev)
return -ENODEV;
mutex_lock(&dev->mutex);
s = comedi_write_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
- err = resize_async_buffer(dev, s, s->async, size);
+ err = resize_async_buffer(dev, s, size);
else
err = -EINVAL;
mutex_unlock(&dev->mutex);
+ comedi_dev_put(dev);
return err ? err : count;
}
static DEVICE_ATTR_RW(write_buffer_kb);
@@ -558,16 +583,17 @@ static void do_become_nonbusy(struct comedi_device *dev,
comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
if (async) {
- comedi_buf_reset(async);
+ comedi_buf_reset(s);
async->inttrig = NULL;
kfree(async->cmd.chanlist);
async->cmd.chanlist = NULL;
+ s->busy = NULL;
+ wake_up_interruptible_all(&s->async->wait_head);
} else {
dev_err(dev->class_dev,
"BUG: (?) do_become_nonbusy called with async=NULL\n");
+ s->busy = NULL;
}
-
- s->busy = NULL;
}
static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
@@ -582,6 +608,21 @@ static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
return ret;
}
+void comedi_device_cancel_all(struct comedi_device *dev)
+{
+ struct comedi_subdevice *s;
+ int i;
+
+ if (!dev->attached)
+ return;
+
+ for (i = 0; i < dev->n_subdevices; i++) {
+ s = &dev->subdevices[i];
+ if (s->async)
+ do_cancel(dev, s);
+ }
+}
+
static int is_device_busy(struct comedi_device *dev)
{
struct comedi_subdevice *s;
@@ -594,7 +635,7 @@ static int is_device_busy(struct comedi_device *dev)
s = &dev->subdevices[i];
if (s->busy)
return 1;
- if (s->async && s->async->mmap_count)
+ if (s->async && comedi_buf_is_mmapped(s))
return 1;
}
@@ -627,6 +668,7 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
return -EBUSY;
if (dev->attached) {
struct module *driver_module = dev->driver->module;
+
comedi_device_detach(dev);
module_put(driver_module);
}
@@ -684,7 +726,8 @@ static int do_bufconfig_ioctl(struct comedi_device *dev,
async = s->async;
if (!async) {
- DPRINTK("subdevice does not have async capability\n");
+ dev_dbg(dev->class_dev,
+ "subdevice does not have async capability\n");
bc.size = 0;
bc.maximum_size = 0;
goto copyback;
@@ -698,7 +741,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev,
}
if (bc.size) {
- retval = resize_async_buffer(dev, s, async, bc.size);
+ retval = resize_async_buffer(dev, s, bc.size);
if (retval < 0)
return retval;
}
@@ -931,7 +974,8 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
async = s->async;
if (!async) {
- DPRINTK("subdevice does not have async capability\n");
+ dev_dbg(dev->class_dev,
+ "subdevice does not have async capability\n");
bi.buf_write_ptr = 0;
bi.buf_read_ptr = 0;
bi.buf_write_count = 0;
@@ -949,8 +993,8 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
return -EACCES;
if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
- bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
- comedi_buf_read_free(async, bi.bytes_read);
+ bi.bytes_read = comedi_buf_read_alloc(s, bi.bytes_read);
+ comedi_buf_read_free(s, bi.bytes_read);
if (comedi_is_subdevice_idle(s) &&
async->buf_write_count == async->buf_read_count) {
@@ -960,8 +1004,8 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
bi.bytes_written =
- comedi_buf_write_alloc(async, bi.bytes_written);
- comedi_buf_write_free(async, bi.bytes_written);
+ comedi_buf_write_alloc(s, bi.bytes_written);
+ comedi_buf_write_free(s, bi.bytes_written);
}
copyback_position:
@@ -1083,19 +1127,20 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
break;
}
if (insn->subdev >= dev->n_subdevices) {
- DPRINTK("%d not usable subdevice\n",
+ dev_dbg(dev->class_dev,
+ "%d not usable subdevice\n",
insn->subdev);
ret = -EINVAL;
break;
}
s = &dev->subdevices[insn->subdev];
if (!s->async) {
- DPRINTK("no async\n");
+ dev_dbg(dev->class_dev, "no async\n");
ret = -EINVAL;
break;
}
if (!s->async->inttrig) {
- DPRINTK("no inttrig\n");
+ dev_dbg(dev->class_dev, "no inttrig\n");
ret = -EAGAIN;
break;
}
@@ -1104,7 +1149,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
ret = 1;
break;
default:
- DPRINTK("invalid insn\n");
+ dev_dbg(dev->class_dev, "invalid insn\n");
ret = -EINVAL;
break;
}
@@ -1113,21 +1158,23 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
unsigned int maxdata;
if (insn->subdev >= dev->n_subdevices) {
- DPRINTK("subdevice %d out of range\n", insn->subdev);
+ dev_dbg(dev->class_dev, "subdevice %d out of range\n",
+ insn->subdev);
ret = -EINVAL;
goto out;
}
s = &dev->subdevices[insn->subdev];
if (s->type == COMEDI_SUBD_UNUSED) {
- DPRINTK("%d not usable subdevice\n", insn->subdev);
+ dev_dbg(dev->class_dev, "%d not usable subdevice\n",
+ insn->subdev);
ret = -EIO;
goto out;
}
/* are we locked? (ioctl lock) */
if (s->lock && s->lock != file) {
- DPRINTK("device locked\n");
+ dev_dbg(dev->class_dev, "device locked\n");
ret = -EACCES;
goto out;
}
@@ -1135,7 +1182,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
ret = comedi_check_chanlist(s, 1, &insn->chanspec);
if (ret < 0) {
ret = -EINVAL;
- DPRINTK("bad chanspec\n");
+ dev_dbg(dev->class_dev, "bad chanspec\n");
goto out;
}
@@ -1148,6 +1195,11 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
switch (insn->insn) {
case INSN_READ:
ret = s->insn_read(dev, s, insn, data);
+ if (ret == -ETIMEDOUT) {
+ dev_dbg(dev->class_dev,
+ "subdevice %d read instruction timed out\n",
+ s->index);
+ }
break;
case INSN_WRITE:
maxdata = s->maxdata_list
@@ -1156,12 +1208,19 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
for (i = 0; i < insn->n; ++i) {
if (data[i] > maxdata) {
ret = -EINVAL;
- DPRINTK("bad data value(s)\n");
+ dev_dbg(dev->class_dev,
+ "bad data value(s)\n");
break;
}
}
- if (ret == 0)
+ if (ret == 0) {
ret = s->insn_write(dev, s, insn, data);
+ if (ret == -ETIMEDOUT) {
+ dev_dbg(dev->class_dev,
+ "subdevice %d write instruction timed out\n",
+ s->index);
+ }
+ }
break;
case INSN_BITS:
if (insn->n != 2) {
@@ -1238,35 +1297,35 @@ static int do_insnlist_ioctl(struct comedi_device *dev,
data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
if (!data) {
- DPRINTK("kmalloc failed\n");
ret = -ENOMEM;
goto error;
}
insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL);
if (!insns) {
- DPRINTK("kmalloc failed\n");
ret = -ENOMEM;
goto error;
}
if (copy_from_user(insns, insnlist.insns,
sizeof(*insns) * insnlist.n_insns)) {
- DPRINTK("copy_from_user failed\n");
+ dev_dbg(dev->class_dev, "copy_from_user failed\n");
ret = -EFAULT;
goto error;
}
for (i = 0; i < insnlist.n_insns; i++) {
if (insns[i].n > MAX_SAMPLES) {
- DPRINTK("number of samples too large\n");
+ dev_dbg(dev->class_dev,
+ "number of samples too large\n");
ret = -EINVAL;
goto error;
}
if (insns[i].insn & INSN_MASK_WRITE) {
if (copy_from_user(data, insns[i].data,
insns[i].n * sizeof(unsigned int))) {
- DPRINTK("copy_from_user failed\n");
+ dev_dbg(dev->class_dev,
+ "copy_from_user failed\n");
ret = -EFAULT;
goto error;
}
@@ -1277,7 +1336,8 @@ static int do_insnlist_ioctl(struct comedi_device *dev,
if (insns[i].insn & INSN_MASK_READ) {
if (copy_to_user(insns[i].data, data,
insns[i].n * sizeof(unsigned int))) {
- DPRINTK("copy_to_user failed\n");
+ dev_dbg(dev->class_dev,
+ "copy_to_user failed\n");
ret = -EFAULT;
goto error;
}
@@ -1357,97 +1417,133 @@ error:
return ret;
}
-static int do_cmd_ioctl(struct comedi_device *dev,
- struct comedi_cmd __user *arg, void *file)
+static int __comedi_get_user_cmd(struct comedi_device *dev,
+ struct comedi_cmd __user *arg,
+ struct comedi_cmd *cmd)
{
- struct comedi_cmd cmd;
struct comedi_subdevice *s;
- struct comedi_async *async;
- int ret = 0;
- unsigned int __user *user_chanlist;
- if (copy_from_user(&cmd, arg, sizeof(cmd))) {
- DPRINTK("bad cmd address\n");
+ if (copy_from_user(cmd, arg, sizeof(*cmd))) {
+ dev_dbg(dev->class_dev, "bad cmd address\n");
return -EFAULT;
}
- /* save user's chanlist pointer so it can be restored later */
- user_chanlist = (unsigned int __user *)cmd.chanlist;
- if (cmd.subdev >= dev->n_subdevices) {
- DPRINTK("%d no such subdevice\n", cmd.subdev);
+ if (cmd->subdev >= dev->n_subdevices) {
+ dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd->subdev);
return -ENODEV;
}
- s = &dev->subdevices[cmd.subdev];
- async = s->async;
+ s = &dev->subdevices[cmd->subdev];
if (s->type == COMEDI_SUBD_UNUSED) {
- DPRINTK("%d not valid subdevice\n", cmd.subdev);
+ dev_dbg(dev->class_dev, "%d not valid subdevice\n",
+ cmd->subdev);
return -EIO;
}
if (!s->do_cmd || !s->do_cmdtest || !s->async) {
- DPRINTK("subdevice %i does not support commands\n",
- cmd.subdev);
+ dev_dbg(dev->class_dev,
+ "subdevice %d does not support commands\n",
+ cmd->subdev);
return -EIO;
}
+ /* make sure channel/gain list isn't too long */
+ if (cmd->chanlist_len > s->len_chanlist) {
+ dev_dbg(dev->class_dev, "channel/gain list too long %d > %d\n",
+ cmd->chanlist_len, s->len_chanlist);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int __comedi_get_user_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int __user *user_chanlist,
+ struct comedi_cmd *cmd)
+{
+ unsigned int *chanlist;
+ int ret;
+
+ /* user_chanlist could be NULL for do_cmdtest ioctls */
+ if (!user_chanlist)
+ return 0;
+
+ chanlist = memdup_user(user_chanlist,
+ cmd->chanlist_len * sizeof(unsigned int));
+ if (IS_ERR(chanlist))
+ return PTR_ERR(chanlist);
+
+ /* make sure each element in channel/gain list is valid */
+ ret = comedi_check_chanlist(s, cmd->chanlist_len, chanlist);
+ if (ret < 0) {
+ kfree(chanlist);
+ return ret;
+ }
+
+ cmd->chanlist = chanlist;
+
+ return 0;
+}
+
+static int do_cmd_ioctl(struct comedi_device *dev,
+ struct comedi_cmd __user *arg, void *file)
+{
+ struct comedi_cmd cmd;
+ struct comedi_subdevice *s;
+ struct comedi_async *async;
+ unsigned int __user *user_chanlist;
+ int ret;
+
+ /* get the user's cmd and do some simple validation */
+ ret = __comedi_get_user_cmd(dev, arg, &cmd);
+ if (ret)
+ return ret;
+
+ /* save user's chanlist pointer so it can be restored later */
+ user_chanlist = (unsigned int __user *)cmd.chanlist;
+
+ s = &dev->subdevices[cmd.subdev];
+ async = s->async;
+
/* are we locked? (ioctl lock) */
if (s->lock && s->lock != file) {
- DPRINTK("subdevice locked\n");
+ dev_dbg(dev->class_dev, "subdevice locked\n");
return -EACCES;
}
/* are we busy? */
if (s->busy) {
- DPRINTK("subdevice busy\n");
+ dev_dbg(dev->class_dev, "subdevice busy\n");
return -EBUSY;
}
- /* make sure channel/gain list isn't too long */
- if (cmd.chanlist_len > s->len_chanlist) {
- DPRINTK("channel/gain list too long %u > %d\n",
- cmd.chanlist_len, s->len_chanlist);
- return -EINVAL;
- }
-
/* make sure channel/gain list isn't too short */
if (cmd.chanlist_len < 1) {
- DPRINTK("channel/gain list too short %u < 1\n",
+ dev_dbg(dev->class_dev, "channel/gain list too short %u < 1\n",
cmd.chanlist_len);
return -EINVAL;
}
async->cmd = cmd;
async->cmd.data = NULL;
- /* load channel/gain list */
- async->cmd.chanlist = memdup_user(user_chanlist,
- async->cmd.chanlist_len * sizeof(int));
- if (IS_ERR(async->cmd.chanlist)) {
- ret = PTR_ERR(async->cmd.chanlist);
- DPRINTK("memdup_user failed with code %d\n", ret);
- goto cleanup;
- }
- /* make sure each element in channel/gain list is valid */
- ret = comedi_check_chanlist(s,
- async->cmd.chanlist_len,
- async->cmd.chanlist);
- if (ret < 0) {
- DPRINTK("bad chanlist\n");
+ /* load channel/gain list */
+ ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &async->cmd);
+ if (ret)
goto cleanup;
- }
ret = s->do_cmdtest(dev, s, &async->cmd);
if (async->cmd.flags & TRIG_BOGUS || ret) {
- DPRINTK("test returned %d\n", ret);
+ dev_dbg(dev->class_dev, "test returned %d\n", ret);
cmd = async->cmd;
/* restore chanlist pointer before copying back */
cmd.chanlist = (unsigned int __force *)user_chanlist;
cmd.data = NULL;
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
- DPRINTK("fault writing cmd\n");
+ dev_dbg(dev->class_dev, "fault writing cmd\n");
ret = -EFAULT;
goto cleanup;
}
@@ -1457,11 +1553,11 @@ static int do_cmd_ioctl(struct comedi_device *dev,
if (!async->prealloc_bufsz) {
ret = -ENOMEM;
- DPRINTK("no buffer (?)\n");
+ dev_dbg(dev->class_dev, "no buffer (?)\n");
goto cleanup;
}
- comedi_buf_reset(async);
+ comedi_buf_reset(s);
async->cb_mask =
COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
@@ -1469,8 +1565,7 @@ static int do_cmd_ioctl(struct comedi_device *dev,
if (async->cmd.flags & TRIG_WAKE_EOS)
async->cb_mask |= COMEDI_CB_EOS;
- comedi_set_subdevice_runflags(s, SRF_USER | SRF_ERROR | SRF_RUNNING,
- SRF_USER | SRF_RUNNING);
+ comedi_set_subdevice_runflags(s, SRF_ERROR | SRF_RUNNING, SRF_RUNNING);
/* set s->busy _after_ setting SRF_RUNNING flag to avoid race with
* comedi_read() or comedi_write() */
@@ -1505,61 +1600,23 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
{
struct comedi_cmd cmd;
struct comedi_subdevice *s;
- int ret = 0;
- unsigned int *chanlist = NULL;
unsigned int __user *user_chanlist;
+ int ret;
+
+ /* get the user's cmd and do some simple validation */
+ ret = __comedi_get_user_cmd(dev, arg, &cmd);
+ if (ret)
+ return ret;
- if (copy_from_user(&cmd, arg, sizeof(cmd))) {
- DPRINTK("bad cmd address\n");
- return -EFAULT;
- }
/* save user's chanlist pointer so it can be restored later */
user_chanlist = (unsigned int __user *)cmd.chanlist;
- if (cmd.subdev >= dev->n_subdevices) {
- DPRINTK("%d no such subdevice\n", cmd.subdev);
- return -ENODEV;
- }
-
s = &dev->subdevices[cmd.subdev];
- if (s->type == COMEDI_SUBD_UNUSED) {
- DPRINTK("%d not valid subdevice\n", cmd.subdev);
- return -EIO;
- }
-
- if (!s->do_cmd || !s->do_cmdtest) {
- DPRINTK("subdevice %i does not support commands\n",
- cmd.subdev);
- return -EIO;
- }
-
- /* make sure channel/gain list isn't too long */
- if (cmd.chanlist_len > s->len_chanlist) {
- DPRINTK("channel/gain list too long %d > %d\n",
- cmd.chanlist_len, s->len_chanlist);
- ret = -EINVAL;
- goto cleanup;
- }
/* load channel/gain list */
- if (cmd.chanlist) {
- chanlist = memdup_user(user_chanlist,
- cmd.chanlist_len * sizeof(int));
- if (IS_ERR(chanlist)) {
- ret = PTR_ERR(chanlist);
- DPRINTK("memdup_user exited with code %d", ret);
- goto cleanup;
- }
-
- /* make sure each element in channel/gain list is valid */
- ret = comedi_check_chanlist(s, cmd.chanlist_len, chanlist);
- if (ret < 0) {
- DPRINTK("bad chanlist\n");
- goto cleanup;
- }
-
- cmd.chanlist = chanlist;
- }
+ ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd);
+ if (ret)
+ return ret;
ret = s->do_cmdtest(dev, s, &cmd);
@@ -1567,12 +1624,9 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
cmd.chanlist = (unsigned int __force *)user_chanlist;
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
- DPRINTK("bad cmd address\n");
+ dev_dbg(dev->class_dev, "bad cmd address\n");
ret = -EFAULT;
- goto cleanup;
}
-cleanup:
- kfree(chanlist);
return ret;
}
@@ -1700,8 +1754,6 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
return -EBUSY;
ret = do_cancel(dev, s);
- if (comedi_get_subdevice_runflags(s) & SRF_USER)
- wake_up_interruptible(&s->async->wait_head);
return ret;
}
@@ -1748,12 +1800,9 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
const unsigned minor = iminor(file_inode(file));
- struct comedi_device *dev = comedi_dev_from_minor(minor);
+ struct comedi_device *dev = file->private_data;
int rc;
- if (!dev)
- return -ENODEV;
-
mutex_lock(&dev->mutex);
/* Device config is special, because it must work on
@@ -1782,7 +1831,7 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
}
if (!dev->attached) {
- DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
+ dev_dbg(dev->class_dev, "no driver attached\n");
rc = -ENODEV;
goto done;
}
@@ -1852,28 +1901,18 @@ done:
static void comedi_vm_open(struct vm_area_struct *area)
{
- struct comedi_async *async;
- struct comedi_device *dev;
+ struct comedi_buf_map *bm;
- async = area->vm_private_data;
- dev = async->subdevice->device;
-
- mutex_lock(&dev->mutex);
- async->mmap_count++;
- mutex_unlock(&dev->mutex);
+ bm = area->vm_private_data;
+ comedi_buf_map_get(bm);
}
static void comedi_vm_close(struct vm_area_struct *area)
{
- struct comedi_async *async;
- struct comedi_device *dev;
-
- async = area->vm_private_data;
- dev = async->subdevice->device;
+ struct comedi_buf_map *bm;
- mutex_lock(&dev->mutex);
- async->mmap_count--;
- mutex_unlock(&dev->mutex);
+ bm = area->vm_private_data;
+ comedi_buf_map_put(bm);
}
static struct vm_operations_struct comedi_vm_ops = {
@@ -1884,22 +1923,27 @@ static struct vm_operations_struct comedi_vm_ops = {
static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
{
const unsigned minor = iminor(file_inode(file));
- struct comedi_device *dev = comedi_dev_from_minor(minor);
+ struct comedi_device *dev = file->private_data;
struct comedi_subdevice *s;
struct comedi_async *async;
+ struct comedi_buf_map *bm = NULL;
unsigned long start = vma->vm_start;
unsigned long size;
int n_pages;
int i;
int retval;
- if (!dev)
- return -ENODEV;
-
- mutex_lock(&dev->mutex);
+ /*
+ * 'trylock' avoids circular dependency with current->mm->mmap_sem
+ * and down-reading &dev->attach_lock should normally succeed without
+ * contention unless the device is in the process of being attached
+ * or detached.
+ */
+ if (!down_read_trylock(&dev->attach_lock))
+ return -EAGAIN;
if (!dev->attached) {
- DPRINTK("no driver configured on comedi%i\n", dev->minor);
+ dev_dbg(dev->class_dev, "no driver attached\n");
retval = -ENODEV;
goto done;
}
@@ -1920,7 +1964,7 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
}
if (vma->vm_pgoff != 0) {
- DPRINTK("comedi: mmap() offset must be 0.\n");
+ dev_dbg(dev->class_dev, "mmap() offset must be 0.\n");
retval = -EINVAL;
goto done;
}
@@ -1936,8 +1980,15 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
}
n_pages = size >> PAGE_SHIFT;
+
+ /* get reference to current buf map (if any) */
+ bm = comedi_buf_map_from_subdev_get(s);
+ if (!bm || n_pages > bm->n_pages) {
+ retval = -EINVAL;
+ goto done;
+ }
for (i = 0; i < n_pages; ++i) {
- struct comedi_buf_page *buf = &async->buf_page_list[i];
+ struct comedi_buf_page *buf = &bm->page_list[i];
if (remap_pfn_range(vma, start,
page_to_pfn(virt_to_page(buf->virt_addr)),
@@ -1949,13 +2000,14 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
}
vma->vm_ops = &comedi_vm_ops;
- vma->vm_private_data = async;
+ vma->vm_private_data = bm;
- async->mmap_count++;
+ vma->vm_ops->open(vma);
retval = 0;
done:
- mutex_unlock(&dev->mutex);
+ up_read(&dev->attach_lock);
+ comedi_buf_map_put(bm); /* put reference to buf map - okay if NULL */
return retval;
}
@@ -1963,16 +2015,13 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
const unsigned minor = iminor(file_inode(file));
- struct comedi_device *dev = comedi_dev_from_minor(minor);
+ struct comedi_device *dev = file->private_data;
struct comedi_subdevice *s;
- if (!dev)
- return -ENODEV;
-
mutex_lock(&dev->mutex);
if (!dev->attached) {
- DPRINTK("no driver configured on comedi%i\n", dev->minor);
+ dev_dbg(dev->class_dev, "no driver attached\n");
goto done;
}
@@ -1980,18 +2029,18 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait)
if (s && s->async) {
poll_wait(file, &s->async->wait_head, wait);
if (!s->busy || !comedi_is_subdevice_running(s) ||
- comedi_buf_read_n_available(s->async) > 0)
+ comedi_buf_read_n_available(s) > 0)
mask |= POLLIN | POLLRDNORM;
}
s = comedi_write_subdevice(dev, minor);
if (s && s->async) {
- unsigned int bps = bytes_per_sample(s->async->subdevice);
+ unsigned int bps = bytes_per_sample(s);
poll_wait(file, &s->async->wait_head, wait);
- comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
+ comedi_buf_write_alloc(s, s->async->prealloc_bufsz);
if (!s->busy || !comedi_is_subdevice_running(s) ||
- comedi_buf_write_n_allocated(s->async) >= bps)
+ comedi_buf_write_n_allocated(s) >= bps)
mask |= POLLOUT | POLLWRNORM;
}
@@ -2008,39 +2057,75 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
int n, m, count = 0, retval = 0;
DECLARE_WAITQUEUE(wait, current);
const unsigned minor = iminor(file_inode(file));
- struct comedi_device *dev = comedi_dev_from_minor(minor);
+ struct comedi_device *dev = file->private_data;
+ bool on_wait_queue = false;
+ bool attach_locked;
+ unsigned int old_detach_count;
- if (!dev)
- return -ENODEV;
+ /* Protect against device detachment during operation. */
+ down_read(&dev->attach_lock);
+ attach_locked = true;
+ old_detach_count = dev->detach_count;
if (!dev->attached) {
- DPRINTK("no driver configured on comedi%i\n", dev->minor);
- return -ENODEV;
+ dev_dbg(dev->class_dev, "no driver attached\n");
+ retval = -ENODEV;
+ goto out;
}
s = comedi_write_subdevice(dev, minor);
- if (!s || !s->async)
- return -EIO;
+ if (!s || !s->async) {
+ retval = -EIO;
+ goto out;
+ }
async = s->async;
if (!s->busy || !nbytes)
- return 0;
- if (s->busy != file)
- return -EACCES;
+ goto out;
+ if (s->busy != file) {
+ retval = -EACCES;
+ goto out;
+ }
add_wait_queue(&async->wait_head, &wait);
+ on_wait_queue = true;
while (nbytes > 0 && !retval) {
set_current_state(TASK_INTERRUPTIBLE);
if (!comedi_is_subdevice_running(s)) {
if (count == 0) {
- mutex_lock(&dev->mutex);
+ struct comedi_subdevice *new_s;
+
if (comedi_is_subdevice_in_error(s))
retval = -EPIPE;
else
retval = 0;
- do_become_nonbusy(dev, s);
+ /*
+ * To avoid deadlock, cannot acquire dev->mutex
+ * while dev->attach_lock is held. Need to
+ * remove task from the async wait queue before
+ * releasing dev->attach_lock, as it might not
+ * be valid afterwards.
+ */
+ remove_wait_queue(&async->wait_head, &wait);
+ on_wait_queue = false;
+ up_read(&dev->attach_lock);
+ attach_locked = false;
+ mutex_lock(&dev->mutex);
+ /*
+ * Become non-busy unless things have changed
+ * behind our back. Checking dev->detach_count
+ * is unchanged ought to be sufficient (unless
+ * there have been 2**32 detaches in the
+ * meantime!), but check the subdevice pointer
+ * as well just in case.
+ */
+ new_s = comedi_write_subdevice(dev, minor);
+ if (dev->attached &&
+ old_detach_count == dev->detach_count &&
+ s == new_s && new_s->async == async)
+ do_become_nonbusy(dev, s);
mutex_unlock(&dev->mutex);
}
break;
@@ -2051,9 +2136,9 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
m = n;
if (async->buf_write_ptr + m > async->prealloc_bufsz)
m = async->prealloc_bufsz - async->buf_write_ptr;
- comedi_buf_write_alloc(async, async->prealloc_bufsz);
- if (m > comedi_buf_write_n_allocated(async))
- m = comedi_buf_write_n_allocated(async);
+ comedi_buf_write_alloc(s, async->prealloc_bufsz);
+ if (m > comedi_buf_write_n_allocated(s))
+ m = comedi_buf_write_n_allocated(s);
if (m < n)
n = m;
@@ -2082,7 +2167,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
n -= m;
retval = -EFAULT;
}
- comedi_buf_write_free(async, n);
+ comedi_buf_write_free(s, n);
count += n;
nbytes -= n;
@@ -2090,8 +2175,12 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
buf += n;
break; /* makes device work like a pipe */
}
+out:
+ if (on_wait_queue)
+ remove_wait_queue(&async->wait_head, &wait);
set_current_state(TASK_RUNNING);
- remove_wait_queue(&async->wait_head, &wait);
+ if (attach_locked)
+ up_read(&dev->attach_lock);
return count ? count : retval;
}
@@ -2104,25 +2193,35 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
int n, m, count = 0, retval = 0;
DECLARE_WAITQUEUE(wait, current);
const unsigned minor = iminor(file_inode(file));
- struct comedi_device *dev = comedi_dev_from_minor(minor);
+ struct comedi_device *dev = file->private_data;
+ unsigned int old_detach_count;
+ bool become_nonbusy = false;
+ bool attach_locked;
- if (!dev)
- return -ENODEV;
+ /* Protect against device detachment during operation. */
+ down_read(&dev->attach_lock);
+ attach_locked = true;
+ old_detach_count = dev->detach_count;
if (!dev->attached) {
- DPRINTK("no driver configured on comedi%i\n", dev->minor);
- return -ENODEV;
+ dev_dbg(dev->class_dev, "no driver attached\n");
+ retval = -ENODEV;
+ goto out;
}
s = comedi_read_subdevice(dev, minor);
- if (!s || !s->async)
- return -EIO;
+ if (!s || !s->async) {
+ retval = -EIO;
+ goto out;
+ }
async = s->async;
if (!s->busy || !nbytes)
- return 0;
- if (s->busy != file)
- return -EACCES;
+ goto out;
+ if (s->busy != file) {
+ retval = -EACCES;
+ goto out;
+ }
add_wait_queue(&async->wait_head, &wait);
while (nbytes > 0 && !retval) {
@@ -2130,7 +2229,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
n = nbytes;
- m = comedi_buf_read_n_available(async);
+ m = comedi_buf_read_n_available(s);
/* printk("%d available\n",m); */
if (async->buf_read_ptr + m > async->prealloc_bufsz)
m = async->prealloc_bufsz - async->buf_read_ptr;
@@ -2140,13 +2239,11 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
if (n == 0) {
if (!comedi_is_subdevice_running(s)) {
- mutex_lock(&dev->mutex);
- do_become_nonbusy(dev, s);
if (comedi_is_subdevice_in_error(s))
retval = -EPIPE;
else
retval = 0;
- mutex_unlock(&dev->mutex);
+ become_nonbusy = true;
break;
}
if (file->f_flags & O_NONBLOCK) {
@@ -2175,8 +2272,8 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
retval = -EFAULT;
}
- comedi_buf_read_alloc(async, n);
- comedi_buf_read_free(async, n);
+ comedi_buf_read_alloc(s, n);
+ comedi_buf_read_free(s, n);
count += n;
nbytes -= n;
@@ -2184,14 +2281,37 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
buf += n;
break; /* makes device work like a pipe */
}
- if (comedi_is_subdevice_idle(s)) {
+ remove_wait_queue(&async->wait_head, &wait);
+ set_current_state(TASK_RUNNING);
+ if (become_nonbusy || comedi_is_subdevice_idle(s)) {
+ struct comedi_subdevice *new_s;
+
+ /*
+ * To avoid deadlock, cannot acquire dev->mutex
+ * while dev->attach_lock is held.
+ */
+ up_read(&dev->attach_lock);
+ attach_locked = false;
mutex_lock(&dev->mutex);
- if (async->buf_read_count - async->buf_write_count == 0)
- do_become_nonbusy(dev, s);
+ /*
+ * Check device hasn't become detached behind our back.
+ * Checking dev->detach_count is unchanged ought to be
+ * sufficient (unless there have been 2**32 detaches in the
+ * meantime!), but check the subdevice pointer as well just in
+ * case.
+ */
+ new_s = comedi_read_subdevice(dev, minor);
+ if (dev->attached && old_detach_count == dev->detach_count &&
+ s == new_s && new_s->async == async) {
+ if (become_nonbusy ||
+ async->buf_read_count - async->buf_write_count == 0)
+ do_become_nonbusy(dev, s);
+ }
mutex_unlock(&dev->mutex);
}
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&async->wait_head, &wait);
+out:
+ if (attach_locked)
+ up_read(&dev->attach_lock);
return count ? count : retval;
}
@@ -2199,101 +2319,58 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
static int comedi_open(struct inode *inode, struct file *file)
{
const unsigned minor = iminor(inode);
- struct comedi_device *dev = comedi_dev_from_minor(minor);
+ struct comedi_device *dev = comedi_dev_get_from_minor(minor);
+ int rc;
if (!dev) {
- DPRINTK("invalid minor number\n");
+ pr_debug("invalid minor number\n");
return -ENODEV;
}
- /* This is slightly hacky, but we want module autoloading
- * to work for root.
- * case: user opens device, attached -> ok
- * case: user opens device, unattached, !in_request_module -> autoload
- * case: user opens device, unattached, in_request_module -> fail
- * case: root opens device, attached -> ok
- * case: root opens device, unattached, in_request_module -> ok
- * (typically called from modprobe)
- * case: root opens device, unattached, !in_request_module -> autoload
- *
- * The last could be changed to "-> ok", which would deny root
- * autoloading.
- */
mutex_lock(&dev->mutex);
- if (dev->attached)
- goto ok;
- if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
- DPRINTK("in request module\n");
- mutex_unlock(&dev->mutex);
- return -ENODEV;
- }
- if (capable(CAP_NET_ADMIN) && dev->in_request_module)
- goto ok;
-
- dev->in_request_module = true;
-
-#ifdef CONFIG_KMOD
- mutex_unlock(&dev->mutex);
- request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
- mutex_lock(&dev->mutex);
-#endif
-
- dev->in_request_module = false;
-
if (!dev->attached && !capable(CAP_NET_ADMIN)) {
- DPRINTK("not attached and not CAP_NET_ADMIN\n");
- mutex_unlock(&dev->mutex);
- return -ENODEV;
+ dev_dbg(dev->class_dev, "not attached and not CAP_NET_ADMIN\n");
+ rc = -ENODEV;
+ goto out;
}
-ok:
- __module_get(THIS_MODULE);
-
- if (dev->attached) {
+ if (dev->attached && dev->use_count == 0) {
if (!try_module_get(dev->driver->module)) {
- module_put(THIS_MODULE);
- mutex_unlock(&dev->mutex);
- return -ENOSYS;
+ rc = -ENOSYS;
+ goto out;
}
- }
-
- if (dev->attached && dev->use_count == 0 && dev->open) {
- int rc = dev->open(dev);
- if (rc < 0) {
- module_put(dev->driver->module);
- module_put(THIS_MODULE);
- mutex_unlock(&dev->mutex);
- return rc;
+ if (dev->open) {
+ rc = dev->open(dev);
+ if (rc < 0) {
+ module_put(dev->driver->module);
+ goto out;
+ }
}
}
dev->use_count++;
+ file->private_data = dev;
+ rc = 0;
+out:
mutex_unlock(&dev->mutex);
-
- return 0;
+ if (rc)
+ comedi_dev_put(dev);
+ return rc;
}
static int comedi_fasync(int fd, struct file *file, int on)
{
- const unsigned minor = iminor(file_inode(file));
- struct comedi_device *dev = comedi_dev_from_minor(minor);
-
- if (!dev)
- return -ENODEV;
+ struct comedi_device *dev = file->private_data;
return fasync_helper(fd, file, on, &dev->async_queue);
}
static int comedi_close(struct inode *inode, struct file *file)
{
- const unsigned minor = iminor(inode);
- struct comedi_device *dev = comedi_dev_from_minor(minor);
+ struct comedi_device *dev = file->private_data;
struct comedi_subdevice *s = NULL;
int i;
- if (!dev)
- return -ENODEV;
-
mutex_lock(&dev->mutex);
if (dev->subdevices) {
@@ -2306,16 +2383,16 @@ static int comedi_close(struct inode *inode, struct file *file)
s->lock = NULL;
}
}
- if (dev->attached && dev->use_count == 1 && dev->close)
- dev->close(dev);
-
- module_put(THIS_MODULE);
- if (dev->attached)
+ if (dev->attached && dev->use_count == 1) {
+ if (dev->close)
+ dev->close(dev);
module_put(dev->driver->module);
+ }
dev->use_count--;
mutex_unlock(&dev->mutex);
+ comedi_dev_put(dev);
return 0;
}
@@ -2346,8 +2423,6 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
unsigned runflags = 0;
unsigned runflags_mask = 0;
- /* DPRINTK("comedi_event 0x%x\n",mask); */
-
if (!comedi_is_subdevice_running(s))
return;
@@ -2368,16 +2443,11 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
}
if (async->cb_mask & s->async->events) {
- if (comedi_get_subdevice_runflags(s) & SRF_USER) {
- wake_up_interruptible(&async->wait_head);
- if (s->subdev_flags & SDF_CMD_READ)
- kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
- if (s->subdev_flags & SDF_CMD_WRITE)
- kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
- } else {
- if (async->cb_func)
- async->cb_func(s->async->events, async->cb_arg);
- }
+ wake_up_interruptible(&async->wait_head);
+ if (s->subdev_flags & SDF_CMD_READ)
+ kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
+ if (s->subdev_flags & SDF_CMD_WRITE)
+ kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
}
s->async->events = 0;
}
@@ -2408,7 +2478,7 @@ struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
if (i == COMEDI_NUM_BOARD_MINORS) {
mutex_unlock(&dev->mutex);
comedi_device_cleanup(dev);
- kfree(dev);
+ comedi_dev_put(dev);
pr_err("comedi: error: ran out of minor numbers for board device files.\n");
return ERR_PTR(-EBUSY);
}
@@ -2416,7 +2486,7 @@ struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
csdev = device_create(comedi_class, hardware_device,
MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
if (!IS_ERR(csdev))
- dev->class_dev = csdev;
+ dev->class_dev = get_device(csdev);
/* Note: dev->mutex needs to be unlocked by the caller. */
return dev;
@@ -2550,6 +2620,7 @@ static int __init comedi_init(void)
/* create devices files for legacy/manual use */
for (i = 0; i < comedi_num_legacy_minors; i++) {
struct comedi_device *dev;
+
dev = comedi_alloc_board_minor(NULL);
if (IS_ERR(dev)) {
comedi_cleanup_board_minors();
diff --git a/drivers/staging/comedi/comedi_internal.h b/drivers/staging/comedi/comedi_internal.h
index fda1a7ba0e1..e978c223f5b 100644
--- a/drivers/staging/comedi/comedi_internal.h
+++ b/drivers/staging/comedi/comedi_internal.h
@@ -15,8 +15,14 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s);
int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned long new_size);
-void comedi_buf_reset(struct comedi_async *async);
-unsigned int comedi_buf_write_n_allocated(struct comedi_async *async);
+void comedi_buf_reset(struct comedi_subdevice *s);
+bool comedi_buf_is_mmapped(struct comedi_subdevice *s);
+void comedi_buf_map_get(struct comedi_buf_map *bm);
+int comedi_buf_map_put(struct comedi_buf_map *bm);
+struct comedi_buf_map *comedi_buf_map_from_subdev_get(
+ struct comedi_subdevice *s);
+unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s);
+void comedi_device_cancel_all(struct comedi_device *dev);
extern unsigned int comedi_default_buf_size_kb;
extern unsigned int comedi_default_buf_maxsize_kb;
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index 143be8076a2..8f4e44bfbe0 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -20,14 +20,13 @@
#define _COMEDIDEV_H
#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/spinlock_types.h>
+#include <linux/rwsem.h>
+#include <linux/kref.h>
#include "comedi.h"
-#define DPRINTK(format, args...) do { \
- if (comedi_debug) \
- pr_debug("comedi: " format, ## args); \
-} while (0)
-
#define COMEDI_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
#define COMEDI_VERSION_CODE COMEDI_VERSION(COMEDI_MAJORVERSION, \
COMEDI_MINORVERSION, COMEDI_MICROVERSION)
@@ -62,31 +61,31 @@ struct comedi_subdevice {
unsigned int *chanlist; /* driver-owned chanlist (not used) */
- int (*insn_read) (struct comedi_device *, struct comedi_subdevice *,
+ int (*insn_read)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*insn_write)(struct comedi_device *, struct comedi_subdevice *,
struct comedi_insn *, unsigned int *);
- int (*insn_write) (struct comedi_device *, struct comedi_subdevice *,
+ int (*insn_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*insn_config)(struct comedi_device *, struct comedi_subdevice *,
struct comedi_insn *, unsigned int *);
- int (*insn_bits) (struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
- int (*insn_config) (struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
-
- int (*do_cmd) (struct comedi_device *, struct comedi_subdevice *);
- int (*do_cmdtest) (struct comedi_device *, struct comedi_subdevice *,
- struct comedi_cmd *);
- int (*poll) (struct comedi_device *, struct comedi_subdevice *);
- int (*cancel) (struct comedi_device *, struct comedi_subdevice *);
+
+ int (*do_cmd)(struct comedi_device *, struct comedi_subdevice *);
+ int (*do_cmdtest)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_cmd *);
+ int (*poll)(struct comedi_device *, struct comedi_subdevice *);
+ int (*cancel)(struct comedi_device *, struct comedi_subdevice *);
/* int (*do_lock)(struct comedi_device *, struct comedi_subdevice *); */
/* int (*do_unlock)(struct comedi_device *, \
struct comedi_subdevice *); */
/* called when the buffer changes */
- int (*buf_change) (struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned long new_size);
+ int (*buf_change)(struct comedi_device *dev,
+ struct comedi_subdevice *s, unsigned long new_size);
- void (*munge) (struct comedi_device *dev, struct comedi_subdevice *s,
- void *data, unsigned int num_bytes,
- unsigned int start_chan_index);
+ void (*munge)(struct comedi_device *dev, struct comedi_subdevice *s,
+ void *data, unsigned int num_bytes,
+ unsigned int start_chan_index);
enum dma_data_direction async_dma_dir;
unsigned int state;
@@ -100,18 +99,20 @@ struct comedi_buf_page {
dma_addr_t dma_addr;
};
-struct comedi_async {
- struct comedi_subdevice *subdevice;
+struct comedi_buf_map {
+ struct device *dma_hw_dev;
+ struct comedi_buf_page *page_list;
+ unsigned int n_pages;
+ enum dma_data_direction dma_dir;
+ struct kref refcount;
+};
+struct comedi_async {
void *prealloc_buf; /* pre-allocated buffer */
unsigned int prealloc_bufsz; /* buffer size, in bytes */
- /* virtual and dma address of each page */
- struct comedi_buf_page *buf_page_list;
- unsigned n_buf_pages; /* num elements in buf_page_list */
+ struct comedi_buf_map *buf_map; /* map of buffer pages */
unsigned int max_bufsize; /* maximum buffer size, bytes */
- /* current number of mmaps of prealloc_buf */
- unsigned int mmap_count;
/* byte count for writer (write completed) */
unsigned int buf_write_count;
@@ -141,13 +142,10 @@ struct comedi_async {
wait_queue_head_t wait_head;
- /* callback stuff */
unsigned int cb_mask;
- int (*cb_func) (unsigned int flags, void *);
- void *cb_arg;
- int (*inttrig) (struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int x);
+ int (*inttrig)(struct comedi_device *dev, struct comedi_subdevice *s,
+ unsigned int x);
};
struct comedi_driver {
@@ -155,9 +153,9 @@ struct comedi_driver {
const char *driver_name;
struct module *module;
- int (*attach) (struct comedi_device *, struct comedi_devconfig *);
- void (*detach) (struct comedi_device *);
- int (*auto_attach) (struct comedi_device *, unsigned long);
+ int (*attach)(struct comedi_device *, struct comedi_devconfig *);
+ void (*detach)(struct comedi_device *);
+ int (*auto_attach)(struct comedi_device *, unsigned long);
/* number of elements in board_name and board_id arrays */
unsigned int num_names;
@@ -173,6 +171,7 @@ struct comedi_device {
struct device *class_dev;
int minor;
+ unsigned int detach_count;
/* hw_dev is passed to dma_alloc_coherent when allocating async buffers
* for subdevices that have async_dma_dir set to something other than
* DMA_NONE */
@@ -181,10 +180,11 @@ struct comedi_device {
const char *board_name;
const void *board_ptr;
bool attached:1;
- bool in_request_module:1;
bool ioenabled:1;
spinlock_t spinlock;
struct mutex mutex;
+ struct rw_semaphore attach_lock;
+ struct kref refcount;
int n_subdevices;
struct comedi_subdevice *subdevices;
@@ -199,8 +199,8 @@ struct comedi_device {
struct fasync_struct *async_queue;
- int (*open) (struct comedi_device *dev);
- void (*close) (struct comedi_device *dev);
+ int (*open)(struct comedi_device *dev);
+ void (*close)(struct comedi_device *dev);
};
static inline const void *comedi_board(const struct comedi_device *dev)
@@ -208,12 +208,6 @@ static inline const void *comedi_board(const struct comedi_device *dev)
return dev->board_ptr;
}
-#ifdef CONFIG_COMEDI_DEBUG
-extern int comedi_debug;
-#else
-static const int comedi_debug;
-#endif
-
/*
* function prototypes
*/
@@ -231,7 +225,8 @@ enum comedi_minor_bits {
static const unsigned COMEDI_SUBDEVICE_MINOR_SHIFT = 4;
static const unsigned COMEDI_SUBDEVICE_MINOR_OFFSET = 1;
-struct comedi_device *comedi_dev_from_minor(unsigned minor);
+struct comedi_device *comedi_dev_get_from_minor(unsigned minor);
+int comedi_dev_put(struct comedi_device *dev);
void init_polling(void);
void cleanup_polling(void);
@@ -240,7 +235,6 @@ void stop_polling(struct comedi_device *);
/* subdevice runflags */
enum subdevice_runflags {
- SRF_USER = 0x00000001,
SRF_RT = 0x00000002,
/* indicates an COMEDI_CB_ERROR event has occurred since the last
* command was started */
@@ -339,23 +333,31 @@ static inline unsigned int bytes_per_sample(const struct comedi_subdevice *subd)
*/
int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev);
-unsigned int comedi_buf_write_alloc(struct comedi_async *, unsigned int);
-unsigned int comedi_buf_write_free(struct comedi_async *, unsigned int);
+unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s, unsigned int n);
+unsigned int comedi_buf_write_free(struct comedi_subdevice *s, unsigned int n);
-unsigned int comedi_buf_read_n_available(struct comedi_async *);
-unsigned int comedi_buf_read_alloc(struct comedi_async *, unsigned int);
-unsigned int comedi_buf_read_free(struct comedi_async *, unsigned int);
+unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s);
+unsigned int comedi_buf_read_alloc(struct comedi_subdevice *s, unsigned int n);
+unsigned int comedi_buf_read_free(struct comedi_subdevice *s, unsigned int n);
-int comedi_buf_put(struct comedi_async *, unsigned short);
-int comedi_buf_get(struct comedi_async *, unsigned short *);
+int comedi_buf_put(struct comedi_subdevice *s, unsigned short x);
+int comedi_buf_get(struct comedi_subdevice *s, unsigned short *x);
-void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset,
+void comedi_buf_memcpy_to(struct comedi_subdevice *s, unsigned int offset,
const void *source, unsigned int num_bytes);
-void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset,
+void comedi_buf_memcpy_from(struct comedi_subdevice *s, unsigned int offset,
void *destination, unsigned int num_bytes);
/* drivers.c - general comedi driver functions */
+#define COMEDI_TIMEOUT_MS 1000
+
+int comedi_timeout(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *,
+ int (*cb)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned long context),
+ unsigned long context);
+
int comedi_dio_insn_config(struct comedi_device *, struct comedi_subdevice *,
struct comedi_insn *, unsigned int *data,
unsigned int mask);
@@ -410,6 +412,7 @@ void comedi_driver_unregister(struct comedi_driver *);
#define PCI_VENDOR_ID_IOTECH 0x1616
#define PCI_VENDOR_ID_CONTEC 0x1221
#define PCI_VENDOR_ID_RTD 0x1435
+#define PCI_VENDOR_ID_HUMUSOFT 0x186c
struct pci_dev;
struct pci_driver;
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index 8f02bf66e20..299726f39e2 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -95,7 +95,7 @@ int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices)
}
EXPORT_SYMBOL_GPL(comedi_alloc_subdevices);
-static void cleanup_device(struct comedi_device *dev)
+static void comedi_device_detach_cleanup(struct comedi_device *dev)
{
int i;
struct comedi_subdevice *s;
@@ -133,10 +133,14 @@ static void cleanup_device(struct comedi_device *dev)
void comedi_device_detach(struct comedi_device *dev)
{
+ comedi_device_cancel_all(dev);
+ down_write(&dev->attach_lock);
dev->attached = false;
+ dev->detach_count++;
if (dev->driver)
dev->driver->detach(dev);
- cleanup_device(dev);
+ comedi_device_detach_cleanup(dev);
+ up_write(&dev->attach_lock);
}
static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s)
@@ -151,6 +155,36 @@ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
}
/**
+ * comedi_timeout() - busy-wait for a driver condition to occur.
+ * @dev: comedi_device struct
+ * @s: comedi_subdevice struct
+ * @insn: comedi_insn struct
+ * @cb: callback to check for the condition
+ * @context: private context from the driver
+ */
+int comedi_timeout(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ int (*cb)(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context),
+ unsigned long context)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(COMEDI_TIMEOUT_MS);
+ int ret;
+
+ while (time_before(jiffies, timeout)) {
+ ret = cb(dev, s, insn, context);
+ if (ret != -EBUSY)
+ return ret; /* success (0) or non EBUSY errno */
+ cpu_relax();
+ }
+ return -ETIMEDOUT;
+}
+EXPORT_SYMBOL_GPL(comedi_timeout);
+
+/**
* comedi_dio_insn_config() - boilerplate (*insn_config) for DIO subdevices.
* @dev: comedi_device struct
* @s: comedi_subdevice struct
@@ -224,6 +258,7 @@ static int insn_rw_emulate_bits(struct comedi_device *dev,
const unsigned base_bitfield_channel =
(chan < channels_per_bitfield) ? 0 : chan;
unsigned int new_data[2];
+
memset(new_data, 0, sizeof(new_data));
memset(&new_insn, 0, sizeof(new_insn));
new_insn.insn = INSN_BITS;
@@ -272,7 +307,6 @@ static int __comedi_device_postconfig_async(struct comedi_device *dev,
return -ENOMEM;
init_waitqueue_head(&async->wait_head);
- async->subdevice = s;
s->async = async;
async->max_bufsize = comedi_default_buf_maxsize_kb * 1024;
@@ -355,8 +389,9 @@ static int comedi_device_postconfig(struct comedi_device *dev)
ret = __comedi_device_postconfig(dev);
if (ret < 0)
return ret;
- smp_wmb();
+ down_write(&dev->attach_lock);
dev->attached = true;
+ up_write(&dev->attach_lock);
return 0;
}
@@ -446,7 +481,7 @@ int comedi_load_firmware(struct comedi_device *dev,
release_firmware(fw);
}
- return ret;
+ return ret < 0 ? ret : 0;
}
EXPORT_SYMBOL_GPL(comedi_load_firmware);
@@ -598,8 +633,12 @@ int comedi_auto_config(struct device *hardware_device,
}
dev = comedi_alloc_board_minor(hardware_device);
- if (IS_ERR(dev))
+ if (IS_ERR(dev)) {
+ dev_warn(hardware_device,
+ "driver '%s' could not create device.\n",
+ driver->driver_name);
return PTR_ERR(dev);
+ }
/* Note: comedi_alloc_board_minor() locked dev->mutex. */
dev->driver = driver;
@@ -607,12 +646,22 @@ int comedi_auto_config(struct device *hardware_device,
ret = driver->auto_attach(dev, context);
if (ret >= 0)
ret = comedi_device_postconfig(dev);
- if (ret < 0)
- comedi_device_detach(dev);
mutex_unlock(&dev->mutex);
- if (ret < 0)
+ if (ret < 0) {
+ dev_warn(hardware_device,
+ "driver '%s' failed to auto-configure device.\n",
+ driver->driver_name);
comedi_release_hardware_device(hardware_device);
+ } else {
+ /*
+ * class_dev should be set properly here
+ * after a successful auto config
+ */
+ dev_info(dev->class_dev,
+ "driver '%s' has successfully auto-configured '%s'.\n",
+ driver->driver_name, dev->board_name);
+ }
return ret;
}
EXPORT_SYMBOL_GPL(comedi_auto_config);
@@ -657,7 +706,7 @@ void comedi_driver_unregister(struct comedi_driver *driver)
/* check for devices using this driver */
for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
- struct comedi_device *dev = comedi_dev_from_minor(i);
+ struct comedi_device *dev = comedi_dev_get_from_minor(i);
if (!dev)
continue;
@@ -671,6 +720,7 @@ void comedi_driver_unregister(struct comedi_driver *driver)
comedi_device_detach(dev);
}
mutex_unlock(&dev->mutex);
+ comedi_dev_put(dev);
}
}
EXPORT_SYMBOL_GPL(comedi_driver_unregister);
diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h
index e3d737cf730..5829b46b757 100644
--- a/drivers/staging/comedi/drivers/8253.h
+++ b/drivers/staging/comedi/drivers/8253.h
@@ -30,106 +30,11 @@
#define I8254_OSC_BASE_2MHZ 500
#define I8254_OSC_BASE_1MHZ 1000
-#define i8253_cascade_ns_to_timer i8253_cascade_ns_to_timer_2div
-
-static inline void i8253_cascade_ns_to_timer_2div_old(int i8253_osc_base,
- unsigned int *d1,
- unsigned int *d2,
- unsigned int *nanosec,
- int round_mode)
-{
- int divider;
- int div1, div2;
- int div1_glb, div2_glb, ns_glb;
- int div1_lub, div2_lub, ns_lub;
- int ns;
-
- divider = (*nanosec + i8253_osc_base / 2) / i8253_osc_base;
-
- /* find 2 integers 1<={x,y}<=65536 such that x*y is
- close to divider */
-
- div1_lub = div2_lub = 0;
- div1_glb = div2_glb = 0;
-
- ns_glb = 0;
- ns_lub = 0xffffffff;
-
- div2 = 0x10000;
- for (div1 = divider / 65536 + 1; div1 < div2; div1++) {
- div2 = divider / div1;
-
- ns = i8253_osc_base * div1 * div2;
- if (ns <= *nanosec && ns > ns_glb) {
- ns_glb = ns;
- div1_glb = div1;
- div2_glb = div2;
- }
-
- div2++;
- if (div2 <= 65536) {
- ns = i8253_osc_base * div1 * div2;
- if (ns > *nanosec && ns < ns_lub) {
- ns_lub = ns;
- div1_lub = div1;
- div2_lub = div2;
- }
- }
- }
-
- *nanosec = div1_lub * div2_lub * i8253_osc_base;
- *d1 = div1_lub & 0xffff;
- *d2 = div2_lub & 0xffff;
- return;
-}
-
-static inline void i8253_cascade_ns_to_timer_power(int i8253_osc_base,
- unsigned int *d1,
- unsigned int *d2,
- unsigned int *nanosec,
- int round_mode)
-{
- int div1, div2;
- int base;
-
- for (div1 = 2; div1 <= (1 << 16); div1 <<= 1) {
- base = i8253_osc_base * div1;
- round_mode &= TRIG_ROUND_MASK;
- switch (round_mode) {
- case TRIG_ROUND_NEAREST:
- default:
- div2 = (*nanosec + base / 2) / base;
- break;
- case TRIG_ROUND_DOWN:
- div2 = (*nanosec) / base;
- break;
- case TRIG_ROUND_UP:
- div2 = (*nanosec + base - 1) / base;
- break;
- }
- if (div2 < 2)
- div2 = 2;
- if (div2 <= 65536) {
- *nanosec = div2 * base;
- *d1 = div1 & 0xffff;
- *d2 = div2 & 0xffff;
- return;
- }
- }
-
- /* shouldn't get here */
- div1 = 0x10000;
- div2 = 0x10000;
- *nanosec = div1 * div2 * i8253_osc_base;
- *d1 = div1 & 0xffff;
- *d2 = div2 & 0xffff;
-}
-
-static inline void i8253_cascade_ns_to_timer_2div(int i8253_osc_base,
- unsigned int *d1,
- unsigned int *d2,
- unsigned int *nanosec,
- int round_mode)
+static inline void i8253_cascade_ns_to_timer(int i8253_osc_base,
+ unsigned int *d1,
+ unsigned int *d2,
+ unsigned int *nanosec,
+ int round_mode)
{
unsigned int divider;
unsigned int div1, div2;
@@ -386,7 +291,7 @@ static inline int i8254_set_mode(unsigned long base_address,
if (counter_number > 2)
return -1;
- if (mode > (I8254_MODE5 | I8254_BINARY))
+ if (mode > (I8254_MODE5 | I8254_BCD))
return -1;
byte = counter_number << 6;
@@ -406,7 +311,7 @@ static inline int i8254_mm_set_mode(void __iomem *base_address,
if (counter_number > 2)
return -1;
- if (mode > (I8254_MODE5 | I8254_BINARY))
+ if (mode > (I8254_MODE5 | I8254_BCD))
return -1;
byte = counter_number << 6;
diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c
index b4009e86341..46113a37413 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -94,7 +94,7 @@ I/O port base address can be found in the output of 'lspci -v'.
struct subdev_8255_private {
unsigned long iobase;
- int (*io) (int, int, int, unsigned long);
+ int (*io)(int, int, int, unsigned long);
};
static int subdev_8255_io(int dir, int port, int data, unsigned long iobase)
@@ -117,7 +117,7 @@ void subdev_8255_interrupt(struct comedi_device *dev,
d = spriv->io(0, _8255_DATA, 0, iobase);
d |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8);
- comedi_buf_put(s->async, d);
+ comedi_buf_put(s, d);
s->async->events |= COMEDI_CB_EOS;
comedi_event(dev, s);
@@ -231,7 +231,7 @@ static int subdev_8255_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
- err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
if (err)
@@ -262,7 +262,7 @@ static int subdev_8255_cancel(struct comedi_device *dev,
}
int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
- int (*io) (int, int, int, unsigned long),
+ int (*io)(int, int, int, unsigned long),
unsigned long iobase)
{
struct subdev_8255_private *spriv;
@@ -289,7 +289,7 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
EXPORT_SYMBOL_GPL(subdev_8255_init);
int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
- int (*io) (int, int, int, unsigned long),
+ int (*io)(int, int, int, unsigned long),
unsigned long iobase)
{
int ret;
@@ -298,6 +298,7 @@ int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
if (ret)
return ret;
+ s->len_chanlist = 1;
s->do_cmdtest = subdev_8255_cmdtest;
s->do_cmd = subdev_8255_cmd;
s->cancel = subdev_8255_cancel;
diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h
index 4f16ea78f86..795d232a6c0 100644
--- a/drivers/staging/comedi/drivers/8255.h
+++ b/drivers/staging/comedi/drivers/8255.h
@@ -22,10 +22,10 @@
#include "../comedidev.h"
int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
- int (*io) (int, int, int, unsigned long),
+ int (*io)(int, int, int, unsigned long),
unsigned long iobase);
int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
- int (*io) (int, int, int, unsigned long),
+ int (*io)(int, int, int, unsigned long),
unsigned long iobase);
void subdev_8255_interrupt(struct comedi_device *dev,
struct comedi_subdevice *s);
diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c
index 432e3f9c330..46a385c29ba 100644
--- a/drivers/staging/comedi/drivers/8255_pci.c
+++ b/drivers/staging/comedi/drivers/8255_pci.c
@@ -56,6 +56,7 @@ Configuration Options: not applicable, uses PCI auto config
#include "../comedidev.h"
#include "8255.h"
+#include "mite.h"
enum pci_8255_boardid {
BOARD_ADLINK_PCI7224,
@@ -63,7 +64,8 @@ enum pci_8255_boardid {
BOARD_ADLINK_PCI7296,
BOARD_CB_PCIDIO24,
BOARD_CB_PCIDIO24H,
- BOARD_CB_PCIDIO48H,
+ BOARD_CB_PCIDIO48H_OLD,
+ BOARD_CB_PCIDIO48H_NEW,
BOARD_CB_PCIDIO96H,
BOARD_NI_PCIDIO96,
BOARD_NI_PCIDIO96B,
@@ -78,6 +80,7 @@ struct pci_8255_boardinfo {
const char *name;
int dio_badr;
int n_8255;
+ unsigned int has_mite:1;
};
static const struct pci_8255_boardinfo pci_8255_boards[] = {
@@ -106,11 +109,16 @@ static const struct pci_8255_boardinfo pci_8255_boards[] = {
.dio_badr = 2,
.n_8255 = 1,
},
- [BOARD_CB_PCIDIO48H] = {
+ [BOARD_CB_PCIDIO48H_OLD] = {
.name = "cb_pci-dio48h",
.dio_badr = 1,
.n_8255 = 2,
},
+ [BOARD_CB_PCIDIO48H_NEW] = {
+ .name = "cb_pci-dio48h",
+ .dio_badr = 2,
+ .n_8255 = 2,
+ },
[BOARD_CB_PCIDIO96H] = {
.name = "cb_pci-dio96h",
.dio_badr = 2,
@@ -120,36 +128,43 @@ static const struct pci_8255_boardinfo pci_8255_boards[] = {
.name = "ni_pci-dio-96",
.dio_badr = 1,
.n_8255 = 4,
+ .has_mite = 1,
},
[BOARD_NI_PCIDIO96B] = {
.name = "ni_pci-dio-96b",
.dio_badr = 1,
.n_8255 = 4,
+ .has_mite = 1,
},
[BOARD_NI_PXI6508] = {
.name = "ni_pxi-6508",
.dio_badr = 1,
.n_8255 = 4,
+ .has_mite = 1,
},
[BOARD_NI_PCI6503] = {
.name = "ni_pci-6503",
.dio_badr = 1,
.n_8255 = 1,
+ .has_mite = 1,
},
[BOARD_NI_PCI6503B] = {
.name = "ni_pci-6503b",
.dio_badr = 1,
.n_8255 = 1,
+ .has_mite = 1,
},
[BOARD_NI_PCI6503X] = {
.name = "ni_pci-6503x",
.dio_badr = 1,
.n_8255 = 1,
+ .has_mite = 1,
},
[BOARD_NI_PXI_6503] = {
.name = "ni_pxi-6503",
.dio_badr = 1,
.n_8255 = 1,
+ .has_mite = 1,
},
};
@@ -157,6 +172,25 @@ struct pci_8255_private {
void __iomem *mmio_base;
};
+static int pci_8255_mite_init(struct pci_dev *pcidev)
+{
+ void __iomem *mite_base;
+ u32 main_phys_addr;
+
+ /* ioremap the MITE registers (BAR 0) temporarily */
+ mite_base = pci_ioremap_bar(pcidev, 0);
+ if (!mite_base)
+ return -ENOMEM;
+
+ /* set data window to main registers (BAR 1) */
+ main_phys_addr = pci_resource_start(pcidev, 1);
+ writel(main_phys_addr | WENAB, mite_base + MITE_IODWBSR);
+
+ /* finished with MITE registers */
+ iounmap(mite_base);
+ return 0;
+}
+
static int pci_8255_mmio(int dir, int port, int data, unsigned long iobase)
{
void __iomem *mmio_base = (void __iomem *)iobase;
@@ -195,6 +229,12 @@ static int pci_8255_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
+ if (board->has_mite) {
+ ret = pci_8255_mite_init(pcidev);
+ if (ret)
+ return ret;
+ }
+
is_mmio = (pci_resource_flags(pcidev, board->dio_badr) &
IORESOURCE_MEM) != 0;
if (is_mmio) {
@@ -229,9 +269,6 @@ static int pci_8255_auto_attach(struct comedi_device *dev,
return ret;
}
- dev_info(dev->class_dev, "%s attached (%d digital i/o channels)\n",
- dev->board_name, board->n_8255 * 24);
-
return 0;
}
@@ -257,13 +294,16 @@ static int pci_8255_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &pci_8255_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(pci_8255_pci_table) = {
+static const struct pci_device_id pci_8255_pci_table[] = {
{ PCI_VDEVICE(ADLINK, 0x7224), BOARD_ADLINK_PCI7224 },
{ PCI_VDEVICE(ADLINK, 0x7248), BOARD_ADLINK_PCI7248 },
{ PCI_VDEVICE(ADLINK, 0x7296), BOARD_ADLINK_PCI7296 },
{ PCI_VDEVICE(CB, 0x0028), BOARD_CB_PCIDIO24 },
{ PCI_VDEVICE(CB, 0x0014), BOARD_CB_PCIDIO24H },
- { PCI_VDEVICE(CB, 0x000b), BOARD_CB_PCIDIO48H },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CB, 0x000b, 0x0000, 0x0000),
+ .driver_data = BOARD_CB_PCIDIO48H_OLD },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_CB, 0x000b, PCI_VENDOR_ID_CB, 0x000b),
+ .driver_data = BOARD_CB_PCIDIO48H_NEW },
{ PCI_VDEVICE(CB, 0x0017), BOARD_CB_PCIDIO96H },
{ PCI_VDEVICE(NI, 0x0160), BOARD_NI_PCIDIO96 },
{ PCI_VDEVICE(NI, 0x1630), BOARD_NI_PCIDIO96B },
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index 94cbd2618fc..0757a82ddcf 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -1,5 +1,6 @@
# Makefile for individual comedi drivers
#
+ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG
# Comedi "helper" modules
@@ -23,6 +24,7 @@ obj-$(CONFIG_COMEDI_PCL818) += pcl818.o
obj-$(CONFIG_COMEDI_PCM3724) += pcm3724.o
obj-$(CONFIG_COMEDI_RTI800) += rti800.o
obj-$(CONFIG_COMEDI_RTI802) += rti802.o
+obj-$(CONFIG_COMEDI_DAC02) += dac02.o
obj-$(CONFIG_COMEDI_DAS16M1) += das16m1.o
obj-$(CONFIG_COMEDI_DAS08_ISA) += das08_isa.o
obj-$(CONFIG_COMEDI_DAS16) += das16.o
@@ -52,7 +54,6 @@ obj-$(CONFIG_COMEDI_PCMDA12) += pcmda12.o
obj-$(CONFIG_COMEDI_PCMMIO) += pcmmio.o
obj-$(CONFIG_COMEDI_PCMUIO) += pcmuio.o
obj-$(CONFIG_COMEDI_MULTIQ3) += multiq3.o
-obj-$(CONFIG_COMEDI_POC) += poc.o
obj-$(CONFIG_COMEDI_S526) += s526.o
# Comedi PCI drivers
@@ -110,6 +111,7 @@ obj-$(CONFIG_COMEDI_NI_PCIMIO) += ni_pcimio.o
obj-$(CONFIG_COMEDI_RTD520) += rtd520.o
obj-$(CONFIG_COMEDI_S626) += s626.o
obj-$(CONFIG_COMEDI_SSV_DNP) += ssv_dnp.o
+obj-$(CONFIG_COMEDI_MF6X4) += mf6x4.o
# Comedi PCMCIA drivers
obj-$(CONFIG_COMEDI_CB_DAS16_CS) += cb_das16_cs.o
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h
index 2ed2da3499f..5c6a11c35de 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.h
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h
@@ -118,18 +118,10 @@ struct addi_private {
int i_IobaseAmcc; /* base+size for AMCC chip */
int i_IobaseAddon; /* addon base address */
int i_IobaseReserved;
- unsigned char b_AiContinuous; /* we do unlimited AI */
unsigned int ui_AiActualScan; /* how many scans we finished */
unsigned int ui_AiNbrofChannels; /* how many channels is measured */
- unsigned int ui_AiScanLength; /* Length of actual scanlist */
- unsigned int *pui_AiChannelList; /* actual chanlist */
unsigned int ui_AiChannelList[32]; /* actual chanlist */
unsigned int ui_AiReadData[32];
- unsigned int ui_AiTimer0; /* Timer Constant for Timer0 */
- unsigned int ui_AiTimer1; /* Timer constant for Timer1 */
- unsigned int ui_AiFlags;
- unsigned int ui_AiDataLength;
- unsigned int ui_AiNbrofScans; /* number of scans to do */
unsigned short us_UseDma; /* To use Dma or not */
unsigned char b_DmaDoubleBuffer; /* we can use double buffering */
unsigned int ui_DmaActualBuffer; /* which buffer is used now */
@@ -145,7 +137,7 @@ struct addi_private {
unsigned short us_OutputRegister; /* Contain data written at iobase + 0 */
unsigned char b_Timer2Mode; /* Specify the timer 2 mode */
unsigned char b_Timer2Interrupt; /* Timer2 interrupt enable or disable */
- unsigned char b_AiCyclicAcquisition; /* indicate cyclic acquisition */
+ unsigned int ai_running:1;
unsigned char b_InterruptMode; /* eoc eos or dma */
unsigned char b_EocEosInterrupt; /* Enable disable eoc eos interrupt */
unsigned int ui_EocEosConversionTime;
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c
index 1128c22e751..28450f65a13 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c
@@ -1,46 +1,24 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.com
-
-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.
-
-@endverbatim
-*/
/*
-
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-------------------------------+---------------------------------------+
- | Project : APCI-035 | Compiler : GCC |
- | Module name : hwdrv_apci035.c | Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-------------------------------+---------------------------------------+
- | Description : Hardware Layer Access For APCI-035 |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +----------+-----------+------------------------------------------------+
- | Date | Author | Description of updates |
- +----------+-----------+------------------------------------------------+
- | | | |
- | | | |
- | | | |
- +----------+-----------+------------------------------------------------+
-*/
+ * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
+ *
+ * ADDI-DATA GmbH
+ * Dieselstrasse 3
+ * D-77833 Ottersweier
+ * Tel: +19(0)7223/9493-0
+ * Fax: +49(0)7223/9493-92
+ * http://www.addi-data.com
+ * info@addi-data.com
+ *
+ * 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.
+ */
/* Card Specific information */
#define APCI035_ADDRESS_RANGE 255
@@ -106,99 +84,66 @@ static struct comedi_lrange range_apci035_ai = {
}
};
-static int i_WatchdogNbr = 0;
-static int i_Temp = 0;
+static int i_WatchdogNbr;
+static int i_Temp;
static int i_Flag = 1;
+
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI035_ConfigTimerWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Configures The Timer , Counter or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[0] : 0 Configure As Timer |
-| 1 Configure As Watchdog |
-| data[1] : Watchdog number
-| data[2] : Time base Unit |
-| data[3] : Reload Value |
-| data[4] : External Trigger |
-| 1:Enable
-| 0:Disable
-| data[5] :External Trigger Level
-| 00 Trigger Disabled
-| 01 Trigger Enabled (Low level)
-| 10 Trigger Enabled (High Level)
-| 11 Trigger Enabled (High/Low level)
-| data[6] : External Gate |
-| 1:Enable
-| 0:Disable
-| data[7] : External Gate level
-| 00 Gate Disabled
-| 01 Gate Enabled (Low level)
-| 10 Gate Enabled (High Level)
-| data[8] :Warning Relay
-| 1: ENABLE
-| 0: DISABLE
-| data[9] :Warning Delay available
-| data[10] :Warning Relay Time unit
-| data[11] :Warning Relay Time Reload value
-| data[12] :Reset Relay
-| 1 : ENABLE
-| 0 : DISABLE
-| data[13] :Interrupt
-| 1 : ENABLE
-| 0 : DISABLE
-|
-|
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures The Timer , Counter or Watchdog
+ *
+ * data[0] 0 = Configure As Timer, 1 = Configure As Watchdog
+ * data[1] Watchdog number
+ * data[2] Time base Unit
+ * data[3] Reload Value
+ * data[4] External Trigger, 1 = Enable, 0 = Disable
+ * data[5] External Trigger Level
+ * 00 = Trigger Disabled
+ * 01 = Trigger Enabled (Low level)
+ * 10 = Trigger Enabled (High Level)
+ * 11 = Trigger Enabled (High/Low level)
+ * data[6] External Gate, 1 = Enable, 0 = Disable
+ * data[7] External Gate level
+ * 00 = Gate Disabled
+ * 01 = Gate Enabled (Low level)
+ * 10 = Gate Enabled (High Level)
+ * data[8] Warning Relay, 1 = Enable, 0 = Disable
+ * data[9] Warning Delay available
+ * data[10] Warning Relay Time unit
+ * data[11] Warning Relay Time Reload value
+ * data[12] Reset Relay, 1 = Enable, 0 = Disable
+ * data[13] Interrupt, 1 = Enable, 0 = Disable
+ */
+static int apci035_timer_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
- unsigned int ui_Status = 0;
- unsigned int ui_Command = 0;
- unsigned int ui_Mode = 0;
+ unsigned int ui_Status;
+ unsigned int ui_Command;
+ unsigned int ui_Mode;
i_Temp = 0;
devpriv->tsk_Current = current;
devpriv->b_TimerSelectMode = data[0];
i_WatchdogNbr = data[1];
- if (data[0] == 0) {
+ if (data[0] == 0)
ui_Mode = 2;
- } else {
+ else
ui_Mode = 0;
- }
-/* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); */
+
ui_Command = 0;
-/* ui_Command = ui_Command & 0xFFFFF9FEUL; */
outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- ui_Command = 0;
+
ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
-/************************/
-/* Set the reload value */
-/************************/
+
+ /* Set the reload value */
outl(data[3], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 4);
-/*********************/
-/* Set the time unit */
-/*********************/
+
+ /* Set the time unit */
outl(data[2], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 8);
if (data[0] == ADDIDATA_TIMER) {
- /******************************/
/* Set the mode : */
/* - Disable the hardware */
/* - Disable the counter mode */
@@ -206,101 +151,82 @@ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev,
/* - Disable the reset */
/* - Enable the timer mode */
/* - Set the timer mode */
- /******************************/
ui_Command =
(ui_Command & 0xFFF719E2UL) | ui_Mode << 13UL | 0x10UL;
- } /* if (data[0] == ADDIDATA_TIMER) */
- else {
- if (data[0] == ADDIDATA_WATCHDOG) {
+ } else if (data[0] == ADDIDATA_WATCHDOG) {
- /******************************/
- /* Set the mode : */
- /* - Disable the hardware */
- /* - Disable the counter mode */
- /* - Disable the warning */
- /* - Disable the reset */
- /* - Disable the timer mode */
- /******************************/
+ /* Set the mode : */
+ /* - Disable the hardware */
+ /* - Disable the counter mode */
+ /* - Disable the warning */
+ /* - Disable the reset */
+ /* - Disable the timer mode */
- ui_Command = ui_Command & 0xFFF819E2UL;
+ ui_Command = ui_Command & 0xFFF819E2UL;
- } else {
- printk("\n The parameter for Timer/watchdog selection is in error\n");
- return -EINVAL;
- }
+ } else {
+ dev_err(dev->class_dev, "The parameter for Timer/watchdog selection is in error\n");
+ return -EINVAL;
}
+
outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- ui_Command = 0;
+
ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
-/********************************/
-/* Disable the hardware trigger */
-/********************************/
+
+ /* Disable the hardware trigger */
ui_Command = ui_Command & 0xFFFFF89FUL;
if (data[4] == ADDIDATA_ENABLE) {
- /**********************************/
+
/* Set the hardware trigger level */
- /**********************************/
ui_Command = ui_Command | (data[5] << 5);
}
outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- ui_Command = 0;
+
ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
-/*****************************/
-/* Disable the hardware gate */
-/*****************************/
+
+ /* Disable the hardware gate */
ui_Command = ui_Command & 0xFFFFF87FUL;
if (data[6] == ADDIDATA_ENABLE) {
-/*******************************/
-/* Set the hardware gate level */
-/*******************************/
+
+ /* Set the hardware gate level */
ui_Command = ui_Command | (data[7] << 7);
}
outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- ui_Command = 0;
+
ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
-/*******************************/
-/* Disable the hardware output */
-/*******************************/
+
+ /* Disable the hardware output */
ui_Command = ui_Command & 0xFFFFF9FBUL;
-/*********************************/
-/* Set the hardware output level */
-/*********************************/
+
+ /* Set the hardware output level */
ui_Command = ui_Command | (data[8] << 2);
outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
if (data[9] == ADDIDATA_ENABLE) {
- /************************/
+
/* Set the reload value */
- /************************/
outl(data[11],
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 24);
- /**********************/
+
/* Set the time unite */
- /**********************/
outl(data[10],
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 28);
}
- ui_Command = 0;
ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- /*******************************/
+
/* Disable the hardware output */
- /*******************************/
ui_Command = ui_Command & 0xFFFFF9F7UL;
- /*********************************/
+
/* Set the hardware output level */
- /*********************************/
ui_Command = ui_Command | (data[12] << 3);
outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- /*************************************/
- /** Enable the watchdog interrupt **/
- /*************************************/
- ui_Command = 0;
+
+ /* Enable the watchdog interrupt */
ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
-/*******************************/
-/* Set the interrupt selection */
-/*******************************/
+
+ /* Set the interrupt selection */
ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16);
ui_Command = (ui_Command & 0xFFFFF9FDUL) | (data[13] << 1);
@@ -310,82 +236,63 @@ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI035_StartStopWriteTimerWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Start / Stop The Selected Timer , or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[0] : 0 - Stop Selected Timer/Watchdog |
-| 1 - Start Selected Timer/Watchdog |
-| 2 - Trigger Selected Timer/Watchdog |
-| 3 - Stop All Timer/Watchdog |
-| 4 - Start All Timer/Watchdog |
-| 5 - Trigger All Timer/Watchdog |
-| |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Start / Stop The Selected Timer , or Watchdog
+ *
+ * data[0]
+ * 0 - Stop Selected Timer/Watchdog
+ * 1 - Start Selected Timer/Watch*dog
+ * 2 - Trigger Selected Timer/Watchdog
+ * 3 - Stop All Timer/Watchdog
+ * 4 - Start All Timer/Watchdog
+ * 5 - Trigger All Timer/Watchdog
+ */
+static int apci035_timer_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
- unsigned int ui_Command = 0;
- int i_Count = 0;
+ unsigned int ui_Command;
+ int i_Count;
if (data[0] == 1) {
ui_Command =
inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- /**********************/
+
/* Start the hardware */
- /**********************/
ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x1UL;
outl(ui_Command,
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- } /* if (data[0]==1) */
+ }
if (data[0] == 2) {
ui_Command =
inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- /***************************/
+
/* Set the trigger command */
- /***************************/
ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x200UL;
outl(ui_Command,
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
}
- if (data[0] == 0) /* Stop The Watchdog */
- {
+ if (data[0] == 0) {
/* Stop The Watchdog */
ui_Command = 0;
-/*
-* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12);
-* ui_Command = ui_Command & 0xFFFFF9FEUL;
-*/
+ /*
+ * ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12);
+ * ui_Command = ui_Command & 0xFFFFF9FEUL;
+ */
outl(ui_Command,
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
- } /* if (data[1]==0) */
- if (data[0] == 3) /* stop all Watchdogs */
- {
+ }
+ if (data[0] == 3) {
+ /* stop all Watchdogs */
ui_Command = 0;
for (i_Count = 1; i_Count <= 4; i_Count++) {
- if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
+ if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG)
ui_Command = 0x2UL;
- } else {
+ else
ui_Command = 0x10UL;
- }
+
i_WatchdogNbr = i_Count;
outl(ui_Command,
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) +
@@ -393,30 +300,29 @@ static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev,
}
}
- if (data[0] == 4) /* start all Watchdogs */
- {
+ if (data[0] == 4) {
+ /* start all Watchdogs */
ui_Command = 0;
for (i_Count = 1; i_Count <= 4; i_Count++) {
- if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
+ if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG)
ui_Command = 0x1UL;
- } else {
+ else
ui_Command = 0x8UL;
- }
+
i_WatchdogNbr = i_Count;
outl(ui_Command,
devpriv->iobase + ((i_WatchdogNbr - 1) * 32) +
0);
}
}
- if (data[0] == 5) /* trigger all Watchdogs */
- {
+ if (data[0] == 5) {
+ /* trigger all Watchdogs */
ui_Command = 0;
for (i_Count = 1; i_Count <= 4; i_Count++) {
- if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
+ if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG)
ui_Command = 0x4UL;
- } else {
+ else
ui_Command = 0x20UL;
- }
i_WatchdogNbr = i_Count;
outl(ui_Command,
@@ -429,109 +335,61 @@ static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI035_ReadTimerWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Read The Selected Timer , Counter or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| |
-+----------------------------------------------------------------------------+
-| Output Parameters : data[0] : software trigger status
-| data[1] : hardware trigger status
-| data[2] : Software clear status
-| data[3] : Overflow status
-| data[4] : Timer actual value
-|
-
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI035_ReadTimerWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Read The Selected Timer , Counter or Watchdog
+ *
+ * data[0] software trigger status
+ * data[1] hardware trigger status
+ * data[2] Software clear status
+ * data[3] Overflow status
+ * data[4] Timer actual value
+ */
+static int apci035_timer_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
- unsigned int ui_Status = 0; /* Status register */
+ unsigned int ui_Status; /* Status register */
i_WatchdogNbr = insn->unused[0];
- /******************/
/* Get the status */
- /******************/
-
ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16);
- /***********************************/
/* Get the software trigger status */
- /***********************************/
-
data[0] = ((ui_Status >> 1) & 1);
- /***********************************/
+
/* Get the hardware trigger status */
- /***********************************/
data[1] = ((ui_Status >> 2) & 1);
- /*********************************/
+
/* Get the software clear status */
- /*********************************/
data[2] = ((ui_Status >> 3) & 1);
- /***************************/
+
/* Get the overflow status */
- /***************************/
data[3] = ((ui_Status >> 0) & 1);
- if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) {
+ if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER)
data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0);
- } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */
-
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI035_ConfigAnalogInput |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Configures The Analog Input Subdevice |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| struct comedi_subdevice *s : Subdevice Pointer |
-| struct comedi_insn *insn : Insn Structure Pointer |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| data[0] : Warning delay value
-| |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI035_ConfigAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures The Analog Input Subdevice
+ *
+ * data[0] Warning delay value
+ */
+static int apci035_ai_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
devpriv->tsk_Current = current;
outl(0x200 | 0, devpriv->iobase + 128 + 0x4);
outl(0, devpriv->iobase + 128 + 0);
-/********************************/
-/* Initialise the warning value */
-/********************************/
+
+ /* Initialise the warning value */
outl(0x300 | 0, devpriv->iobase + 128 + 0x4);
outl((data[0] << 8), devpriv->iobase + 128 + 0);
outl(0x200000UL, devpriv->iobase + 128 + 12);
@@ -540,145 +398,88 @@ static int i_APCI035_ConfigAnalogInput(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI035_ReadAnalogInput |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Read value of the selected channel |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int ui_NoOfChannels : No Of Channels To read |
-| unsigned int *data : Data Pointer to read status |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-| data[0] : Digital Value Of Input |
-| |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI035_ReadAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Read value of the selected channel
+ *
+ * data[0] Digital Value Of Input
+ */
+static int apci035_ai_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
- unsigned int ui_CommandRegister = 0;
+ unsigned int ui_CommandRegister;
-/******************/
-/* Set the start */
-/******************/
+ /* Set the start */
ui_CommandRegister = 0x80000;
- /******************************/
+
/* Write the command register */
- /******************************/
outl(ui_CommandRegister, devpriv->iobase + 128 + 8);
-/***************************************/
-/* Read the digital value of the input */
-/***************************************/
+ /* Read the digital value of the input */
data[0] = inl(devpriv->iobase + 128 + 28);
return insn->n;
}
-/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI035_Reset(struct comedi_device *dev) |
-| |
-+----------------------------------------------------------------------------+
-| Task :Resets the registers of the card |
-+----------------------------------------------------------------------------+
-| Input Parameters : |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI035_Reset(struct comedi_device *dev)
+static int apci035_reset(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
- int i_Count = 0;
+ int i_Count;
for (i_Count = 1; i_Count <= 4; i_Count++) {
i_WatchdogNbr = i_Count;
- outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); /* stop all timers */
+
+ /* stop all timers */
+ outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0);
}
outl(0x0, devpriv->iobase + 128 + 12); /* Disable the warning delay */
return 0;
}
-/*
-+----------------------------------------------------------------------------+
-| Function Name : static void v_APCI035_Interrupt |
-| (int irq , void *d) |
-+----------------------------------------------------------------------------+
-| Task : Interrupt processing Routine |
-+----------------------------------------------------------------------------+
-| Input Parameters : int irq : irq number |
-| void *d : void pointer |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static void v_APCI035_Interrupt(int irq, void *d)
+static void apci035_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct addi_private *devpriv = dev->private;
- unsigned int ui_StatusRegister1 = 0;
- unsigned int ui_StatusRegister2 = 0;
- unsigned int ui_ReadCommand = 0;
- unsigned int ui_ChannelNumber = 0;
- unsigned int ui_DigitalTemperature = 0;
+ unsigned int ui_StatusRegister1;
+ unsigned int ui_StatusRegister2;
+ unsigned int ui_ReadCommand;
+ unsigned int ui_ChannelNumber;
+ unsigned int ui_DigitalTemperature;
if (i_Temp == 1) {
i_WatchdogNbr = i_Flag;
i_Flag = i_Flag + 1;
}
- /**************************************/
+
/* Read the interrupt status register of temperature Warning */
- /**************************************/
ui_StatusRegister1 = inl(devpriv->iobase + 128 + 16);
- /**************************************/
- /* Read the interrupt status register for Watchdog/timer */
- /**************************************/
+ /* Read the interrupt status register for Watchdog/timer */
ui_StatusRegister2 =
inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 20);
- if ((((ui_StatusRegister1) & 0x8) == 0x8)) /* Test if warning relay interrupt */
- {
- /**********************************/
+ /* Test if warning relay interrupt */
+ if ((((ui_StatusRegister1) & 0x8) == 0x8)) {
+
/* Disable the temperature warning */
- /**********************************/
ui_ReadCommand = inl(devpriv->iobase + 128 + 12);
ui_ReadCommand = ui_ReadCommand & 0xFFDF0000UL;
outl(ui_ReadCommand, devpriv->iobase + 128 + 12);
- /***************************/
+
/* Read the channel number */
- /***************************/
ui_ChannelNumber = inl(devpriv->iobase + 128 + 60);
- /**************************************/
+
/* Read the digital temperature value */
- /**************************************/
ui_DigitalTemperature = inl(devpriv->iobase + 128 + 60);
- send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
- } /* if (((ui_StatusRegister1 & 0x8) == 0x8)) */
- else {
- if ((ui_StatusRegister2 & 0x1) == 0x1) {
- send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
- }
- } /* else if (((ui_StatusRegister1 & 0x8) == 0x8)) */
+ /* send signal to the sample */
+ send_sig(SIGIO, devpriv->tsk_Current, 0);
+
+ } else if ((ui_StatusRegister2 & 0x1) == 0x1) {
+ /* send signal to the sample */
+ send_sig(SIGIO, devpriv->tsk_Current, 0);
+ }
return;
}
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
index 054910511e9..a633957890d 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
@@ -1,48 +1,25 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.com
-
-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.
-
-@endverbatim
-*/
/*
-
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-------------------------------+---------------------------------------+
- | Project : APCI-1500 | Compiler : GCC |
- | Module name : hwdrv_apci1500.c| Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-------------------------------+---------------------------------------+
- | Description : Hardware Layer Access For APCI-1500 |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +----------+-----------+------------------------------------------------+
- | Date | Author | Description of updates |
- +----------+-----------+------------------------------------------------+
- | | | |
- | | | |
- | | | |
- +----------+-----------+------------------------------------------------+
-*/
-
-/********* Definitions for APCI-1500 card *****/
+ * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
+ *
+ * ADDI-DATA GmbH
+ * Dieselstrasse 3
+ * D-77833 Ottersweier
+ * Tel: +19(0)7223/9493-0
+ * Fax: +49(0)7223/9493-92
+ * http://www.addi-data.com
+ * info@addi-data.com
+ *
+ * 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.
+ *
+ */
/* Card Specific information */
#define APCI1500_ADDRESS_RANGE 4
@@ -141,99 +118,45 @@ enum {
APCI1500_RW_PORT_B_PATTERN_MASK
};
-static int i_TimerCounter1Init = 0;
-static int i_TimerCounter2Init = 0;
-static int i_WatchdogCounter3Init = 0;
-static int i_Event1Status = 0, i_Event2Status = 0;
-static int i_TimerCounterWatchdogInterrupt = 0;
-static int i_Logic = 0, i_CounterLogic = 0;
-static int i_InterruptMask = 0;
-static int i_InputChannel = 0;
-static int i_TimerCounter1Enabled = 0, i_TimerCounter2Enabled = 0,
- i_WatchdogCounter3Enabled = 0;
+static int i_TimerCounter1Init;
+static int i_TimerCounter2Init;
+static int i_WatchdogCounter3Init;
+static int i_Event1Status, i_Event2Status;
+static int i_TimerCounterWatchdogInterrupt;
+static int i_Logic, i_CounterLogic;
+static int i_InterruptMask;
+static int i_InputChannel;
+static int i_TimerCounter1Enabled, i_TimerCounter2Enabled,
+ i_WatchdogCounter3Enabled;
/*
- +----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_ConfigDigitalInputEvent |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : An event can be generated for each port. |
-| The first event is related to the first 8 channels |
-| (port 1) and the second to the following 6 channels |
-| (port 2). An interrupt is generated when one or both |
-| events have occurred |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[0] :Number of the input port on |
-| which the event will take place |
-| (1 or 2)
-| data[1] : The event logic for port 1 has |
-| three possibilities |
-| :0 APCI1500_AND :This logic |
-| links |
-| the inputs |
-| with an AND |
-| logic. |
-| 1 APCI1500_OR :This logic |
-| links |
-| the inputs |
-| with a |
-| OR logic. |
-| 2 APCI1500_OR_PRIORITY |
-| :This logic |
-| links |
-| the inputs |
-| with a |
-| priority |
-| OR logic. |
-| Input 1 |
-| has the |
-| highest |
-| priority |
-| level and |
-| input 8 |
-| the smallest|
-| For the second port the user has|
-| 1 possibility: |
-| APCI1500_OR :This logic |
-| links |
-| the inputs |
-| with a |
-| polarity |
-| OR logic |
-| data[2] : These 8-character word for port1|
-| and 6-character word for port 2 |
-| give the mask of the event. |
-| Each place gives the state |
-| of the input channels and can |
-| have one of these six characters|
-| |
-| 0 : This input must be on 0 |
-| 1 : This input must be on 1 |
-| 2 : This input reacts to |
-| a falling edge |
-| 3 : This input reacts to a |
-| rising edge |
-| 4 : This input reacts to both edges |
-|
-| 5 : This input is not |
-| used for event |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * An event can be generated for each port. The first event is related to the
+ * first 8 channels (port 1) and the second to the following 6 channels (port 2)
+ * An interrupt is generated when one or both events have occurred.
+ *
+ * data[0] Number of the input port on which the event will take place (1 or 2)
+ * data[1] The event logic for port 1 has three possibilities:
+ * APCI1500_AND This logic links the inputs with an AND logic.
+ * APCI1500_OR This logic links the inputs with a OR logic.
+ * APCI1500_OR_PRIORITY This logic links the inputs with a priority OR
+ * logic. Input 1 has the highest priority level
+ * and input 8 the smallest.
+ * For the second port the user has 1 possibility:
+ * APCI1500_OR This logic links the inputs with a polarity OR logic
+ * data[2] These 8-character word for port1 and 6-character word for port 2
+ * give the mask of the event. Each place gives the state of the input
+ * channels and can have one of these six characters
+ * 0 This input must be on 0
+ * 1 This input must be on 1
+ * 2 This input reacts to a falling edge
+ * 3 This input reacts to a rising edge
+ * 4 This input reacts to both edges
+ * 5 This input is not used for event
+ */
+static int apci1500_di_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
int i_PatternPolarity = 0, i_PatternTransition = 0, i_PatternMask = 0;
@@ -241,14 +164,10 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
int i_PatternTransitionCount = 0, i_RegValue;
int i;
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Disables the main interrupt on the board */
- /**********************************************/
outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
if (data[0] == 1) {
@@ -259,7 +178,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
i_MaxChannel = 6;
} /* if(data[0]==2) */
else {
- printk("\nThe specified port event does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified port event does not exist\n");
return -EINVAL;
} /* else if(data[0]==2) */
} /* else if (data[0] == 1) */
@@ -274,7 +194,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
data[1] = APCI1500_OR_PRIORITY;
break;
default:
- printk("\nThe specified interrupt logic does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified interrupt logic does not exist\n");
return -EINVAL;
} /* switch(data[1]); */
@@ -318,37 +239,30 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
case 5:
break;
default:
- printk("\nThe option indicated in the event mask does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The option indicated in the event mask does not exist\n");
return -EINVAL;
} /* switch(i_EventMask) */
} /* for (i_Count = i_MaxChannel; i_Count >0;i_Count --) */
if (data[0] == 1) {
- /****************************/
/* Test the interrupt logic */
- /****************************/
if (data[1] == APCI1500_AND ||
data[1] == APCI1500_OR ||
data[1] == APCI1500_OR_PRIORITY) {
- /**************************************/
/* Tests if a transition was declared */
/* for a OR PRIORITY logic */
- /**************************************/
if (data[1] == APCI1500_OR_PRIORITY
&& i_PatternTransition != 0) {
- /********************************************/
- /* Transition error on an OR PRIORITY logic */
- /********************************************/
- printk("\nTransition error on an OR PRIORITY logic\n");
+ dev_warn(dev->hw_dev,
+ "Transition error on an OR PRIORITY logic\n");
return -EINVAL;
} /* if (data[1]== APCI1500_OR_PRIORITY && i_PatternTransition != 0) */
- /*************************************/
/* Tests if more than one transition */
/* was declared for an AND logic */
- /*************************************/
if (data[1] == APCI1500_AND) {
for (i_Count = 0; i_Count < 8; i_Count++) {
@@ -360,29 +274,21 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
} /* for (i_Count = 0; i_Count < 8; i_Count++) */
if (i_PatternTransitionCount > 1) {
- /****************************************/
- /* Transition error on an AND logic */
- /****************************************/
- printk("\n Transition error on an AND logic\n");
+ dev_warn(dev->hw_dev,
+ "Transition error on an AND logic\n");
return -EINVAL;
} /* if (i_PatternTransitionCount > 1) */
} /* if (data[1]== APCI1500_AND) */
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************/
/* Disable Port A */
- /******************/
outb(0xF0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Selects the polarity register of port 1 */
- /**********************************************/
outb(APCI1500_RW_PORT_A_PATTERN_POLARITY,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -390,20 +296,16 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*********************************************/
/* Selects the pattern mask register of */
/* port 1 */
- /*********************************************/
outb(APCI1500_RW_PORT_A_PATTERN_MASK,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
outb(i_PatternMask,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************************/
/* Selects the pattern transition register */
/* of port 1 */
- /********************************************/
outb(APCI1500_RW_PORT_A_PATTERN_TRANSITION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -411,10 +313,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************/
/* Selects the mode specification mask */
/* register of port 1 */
- /******************************************/
outb(APCI1500_RW_PORT_A_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -422,17 +322,13 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************/
/* Selects the mode specification mask */
/* register of port 1 */
- /******************************************/
outb(APCI1500_RW_PORT_A_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************/
/* Port A new mode */
- /**********************/
i_RegValue = (i_RegValue & 0xF9) | data[1] | 0x9;
outb(i_RegValue,
@@ -441,53 +337,40 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
i_Event1Status = 1;
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*****************/
/* Enable Port A */
- /*****************/
outb(0xF4,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
} /* if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */
else {
- printk("\nThe choice for interrupt logic does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The choice for interrupt logic does not exist\n");
return -EINVAL;
} /* else }// if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */
} /* if (data[0]== 1) */
- /************************************/
/* Test if event setting for port 2 */
- /************************************/
if (data[0] == 2) {
- /************************/
/* Test the event logic */
- /************************/
if (data[1] == APCI1500_OR) {
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************/
/* Disable Port B */
- /******************/
outb(0x74,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************/
/* Selects the mode specification mask */
/* register of port B */
- /****************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -495,10 +378,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************/
/* Selects the mode specification mask */
/* register of port B */
- /******************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -507,37 +388,29 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************/
/* Selects error channels 1 and 2 */
- /**********************************/
i_PatternMask = (i_PatternMask | 0xC0);
i_PatternPolarity = (i_PatternPolarity | 0xC0);
i_PatternTransition = (i_PatternTransition | 0xC0);
- /**********************************************/
/* Selects the polarity register of port 2 */
- /**********************************************/
outb(APCI1500_RW_PORT_B_PATTERN_POLARITY,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
outb(i_PatternPolarity,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Selects the pattern transition register */
/* of port 2 */
- /**********************************************/
outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
outb(i_PatternTransition,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Selects the pattern Mask register */
/* of port 2 */
- /**********************************************/
outb(APCI1500_RW_PORT_B_PATTERN_MASK,
devpriv->iobase +
@@ -546,20 +419,16 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************/
/* Selects the mode specification mask */
/* register of port 2 */
- /******************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue =
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************/
/* Selects the mode specification mask */
/* register of port 2 */
- /******************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -569,23 +438,20 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
APCI1500_Z8536_CONTROL_REGISTER);
i_Event2Status = 1;
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*****************/
/* Enable Port B */
- /*****************/
outb(0xF4,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
} /* if (data[1] == APCI1500_OR) */
else {
- printk("\nThe choice for interrupt logic does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The choice for interrupt logic does not exist\n");
return -EINVAL;
} /* elseif (data[1] == APCI1500_OR) */
} /* if(data[0]==2) */
@@ -594,31 +460,15 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_StartStopInputEvent |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Allows or disallows a port event |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int ui_Channel : Channel number to read |
-| unsigned int *data : Data Pointer to read status |
-| data[0] :0 Start input event
-| 1 Stop input event
-| data[1] :No of port (1 or 2)
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Allows or disallows a port event
+ *
+ * data[0] 0 = Start input event, 1 = Stop input event
+ * data[1] Number of port (1 or 2)
+ */
+static int apci1500_di_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
int i_Event1InterruptStatus = 0, i_Event2InterruptStatus =
@@ -626,48 +476,30 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev,
switch (data[0]) {
case START:
- /*************************/
/* Tests the port number */
- /*************************/
if (data[1] == 1 || data[1] == 2) {
- /***************************/
/* Test if port 1 selected */
- /***************************/
if (data[1] == 1) {
- /*****************************/
/* Test if event initialised */
- /*****************************/
if (i_Event1Status == 1) {
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************/
/* Disable Port A */
- /******************/
outb(0xF0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************************/
/* Selects the command and status register of */
/* port 1 */
- /***************************************************/
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************/
/* Allows the pattern interrupt */
- /*************************************/
outb(0xC0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************/
/* Enable Port A */
- /*****************/
outb(0xF4,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -680,185 +512,142 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev,
APCI1500_Z8536_CONTROL_REGISTER);
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Authorizes the main interrupt on the board */
- /**********************************************/
outb(0xD0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
} /* if(i_Event1Status==1) */
else {
- printk("\nEvent 1 not initialised\n");
+ dev_warn(dev->hw_dev,
+ "Event 1 not initialised\n");
return -EINVAL;
} /* else if(i_Event1Status==1) */
} /* if (data[1]==1) */
if (data[1] == 2) {
if (i_Event2Status == 1) {
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************/
/* Disable Port B */
- /******************/
outb(0x74,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************************/
/* Selects the command and status register of */
/* port 2 */
- /***************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************/
/* Allows the pattern interrupt */
- /*************************************/
outb(0xC0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************/
/* Enable Port B */
- /*****************/
outb(0xF4,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Authorizes the main interrupt on the board */
- /**********************************************/
outb(0xD0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
i_Event2InterruptStatus = 1;
} /* if(i_Event2Status==1) */
else {
- printk("\nEvent 2 not initialised\n");
+ dev_warn(dev->hw_dev,
+ "Event 2 not initialised\n");
return -EINVAL;
} /* else if(i_Event2Status==1) */
} /* if(data[1]==2) */
} /* if (data[1] == 1 || data[0] == 2) */
else {
- printk("\nThe port parameter is in error\n");
+ dev_warn(dev->hw_dev,
+ "The port parameter is in error\n");
return -EINVAL;
} /* else if (data[1] == 1 || data[0] == 2) */
break;
case STOP:
- /*************************/
/* Tests the port number */
- /*************************/
if (data[1] == 1 || data[1] == 2) {
- /***************************/
/* Test if port 1 selected */
- /***************************/
if (data[1] == 1) {
- /*****************************/
/* Test if event initialised */
- /*****************************/
if (i_Event1Status == 1) {
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************/
/* Disable Port A */
- /******************/
outb(0xF0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************************/
/* Selects the command and status register of */
/* port 1 */
- /***************************************************/
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************/
/* Inhibits the pattern interrupt */
- /*************************************/
outb(0xE0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************/
/* Enable Port A */
- /*****************/
outb(0xF4,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
i_Event1InterruptStatus = 0;
} /* if(i_Event1Status==1) */
else {
- printk("\nEvent 1 not initialised\n");
+ dev_warn(dev->hw_dev,
+ "Event 1 not initialised\n");
return -EINVAL;
} /* else if(i_Event1Status==1) */
} /* if (data[1]==1) */
if (data[1] == 2) {
- /*****************************/
/* Test if event initialised */
- /*****************************/
if (i_Event2Status == 1) {
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************/
/* Disable Port B */
- /******************/
outb(0x74,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************************/
/* Selects the command and status register of */
/* port 2 */
- /***************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************/
/* Inhibits the pattern interrupt */
- /*************************************/
outb(0xE0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************************/
/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- /*****************************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************/
/* Enable Port B */
- /*****************/
outb(0xF4,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
i_Event2InterruptStatus = 0;
} /* if(i_Event2Status==1) */
else {
- printk("\nEvent 2 not initialised\n");
+ dev_warn(dev->hw_dev,
+ "Event 2 not initialised\n");
return -EINVAL;
} /* else if(i_Event2Status==1) */
} /* if(data[1]==2) */
} /* if (data[1] == 1 || data[1] == 2) */
else {
- printk("\nThe port parameter is in error\n");
+ dev_warn(dev->hw_dev,
+ "The port parameter is in error\n");
return -EINVAL;
} /* else if (data[1] == 1 || data[1] == 2) */
break;
default:
- printk("\nThe option of START/STOP logic does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The option of START/STOP logic does not exist\n");
return -EINVAL;
} /* switch(data[0]) */
@@ -866,35 +655,17 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_Initialisation |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Return the status of the digital input |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int ui_Channel : Channel number to read |
-| unsigned int *data : Data Pointer to read status |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_Initialisation(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Return the status of the digital input
+ */
+static int apci1500_di_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
int i_DummyRead = 0;
- /******************/
/* Software reset */
- /******************/
i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
@@ -902,16 +673,12 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the master configuration control register */
- /*****************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the mode specification register of port A */
- /*****************************************************/
outb(APCI1500_RW_PORT_A_SPECIFICATION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
@@ -943,9 +710,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
/* Deletes the register */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the mode specification register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
@@ -975,9 +740,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
/* Deletes the register */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the data path polarity register of port C */
- /*****************************************************/
outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* High level of port C means 1 */
@@ -992,9 +755,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes it */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************************/
/* Selects the command and status register of timer 1 */
- /******************************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes IP and IUS */
@@ -1004,9 +765,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deactivates the interrupt management of timer 1 */
outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************************/
/* Selects the command and status register of timer 2 */
- /******************************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes IP and IUS */
@@ -1016,9 +775,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deactivates Timer 2 interrupt management: */
outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************************/
/* Selects the command and status register of timer 3 */
- /******************************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes IP and IUS */
@@ -1028,9 +785,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deactivates interrupt management of timer 3: */
outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes all interrupts */
@@ -1051,37 +806,15 @@ static int apci1500_di_insn_bits(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_ConfigDigitalOutputErrorInterrupt
-| (struct comedi_device *dev,struct comedi_subdevice *s struct comedi_insn
-| *insn,unsigned int *data) |
-| |
-+----------------------------------------------------------------------------+
-| Task : Configures the digital output memory and the digital
-| output error interrupt |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| struct comedi_subdevice *s, :pointer to subdevice structure
-| struct comedi_insn *insn :pointer to insn structure |
-| data[0] :1:Memory on |
-| 0:Memory off |
-| data[1] :1 Enable the voltage error interrupt
-| :0 Disable the voltage error interrupt |
-| |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures the digital output memory and the digital output error interrupt
+ *
+ * data[1] 1 = Enable the voltage error interrupt
+ * 2 = Disable the voltage error interrupt
+ */
+static int apci1500_do_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
@@ -1090,31 +823,15 @@ static int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *de
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_WriteDigitalOutput |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Writes port value To the selected port |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int ui_NoOfChannels : No Of Channels To Write |
-| unsigned int *data : Data Pointer to read status |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Writes port value to the selected port
+ */
+static int apci1500_do_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
- static unsigned int ui_Temp = 0;
+ static unsigned int ui_Temp;
unsigned int ui_Temp1;
unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */
@@ -1165,7 +882,9 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev,
APCI1500_DIGITAL_OP);
} /* if(data[1]==1) */
else {
- printk("\nSpecified channel not supported\n");
+ dev_warn(dev->hw_dev,
+ "Specified channel not supported\n");
+ return -EINVAL;
} /* else if(data[1]==1) */
} /* elseif(data[1]==0) */
} /* if(data[3]==0) */
@@ -1242,12 +961,15 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev,
APCI1500_DIGITAL_OP);
} /* if(data[1]==1) */
else {
- printk("\nSpecified channel not supported\n");
+ dev_warn(dev->hw_dev,
+ "Specified channel not supported\n");
+ return -EINVAL;
} /* else if(data[1]==1) */
} /* elseif(data[1]==0) */
} /* if(data[3]==1); */
else {
- printk("\nSpecified functionality does not exist\n");
+ dev_warn(dev->hw_dev,
+ "Specified functionality does not exist\n");
return -EINVAL;
} /* if else data[3]==1) */
} /* if else data[3]==0) */
@@ -1256,57 +978,23 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_ConfigCounterTimerWatchdog(comedi_device
-| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)|
-| |
-+----------------------------------------------------------------------------+
-| Task : Configures The Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| struct comedi_subdevice *s, :pointer to subdevice structure
-| struct comedi_insn *insn :pointer to insn structure |
-| unsigned int *data : Data Pointer to read status data[0] : 2 APCI1500_1_8_KHZ
-| 1 APCI1500_3_6_KHZ |
-| 0 APCI1500_115_KHZ
-| data[1] : 0 Counter1/Timer1
-| 1 Counter2/Timer2
-| 2 Counter3/Watchdog
-| data[2] : 0 Counter
-| 1 Timer/Watchdog
-| data[3] : This parameter has |
-| two meanings. |
-| - If the counter/timer |
-| is used as a counter |
-| the limit value of |
-| the counter is given |
-| |
-| - If the counter/timer |
-| is used as a timer, |
-| the divider factor |
-| for the output is |
-| given.
-| data[4] : 0 APCI1500_CONTINUOUS
-| 1 APCI1500_SINGLE
-| data[5] : 0 Software Trigger
-| 1 Hardware Trigger
-|
-| data[6] :0 Software gate
-| 1 Hardware gate
-| data[7] :0 Interrupt Disable
-| 1 Interrupt Enable
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures The Watchdog
+ *
+ * data[0] 0 = APCI1500_115_KHZ, 1 = APCI1500_3_6_KHZ, 2 = APCI1500_1_8_KHZ
+ * data[1] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog
+ * data[2] 0 = Counter, 1 = Timer/Watchdog
+ * data[3] This parameter has two meanings. If the counter/timer is used as
+ * a counter the limit value of the counter is given. If the counter/timer
+ * is used as a timer, the divider factor for the output is given.
+ * data[4] 0 = APCI1500_CONTINUOUS, 1 = APCI1500_SINGLE
+ * data[5] 0 = Software Trigger, 1 = Hardware Trigger
+ * data[6] 0 = Software gate, 1 = Hardware gate
+ * data[7] 0 = Interrupt Disable, 1 = Interrupt Enable
+ */
+static int apci1500_timer_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
int i_TimerCounterMode, i_MasterConfiguration;
@@ -1319,7 +1007,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
} /* if(data[0]==0||data[0]==1||data[0]==2) */
else {
if (data[0] != 3) {
- printk("\nThe option for input clock selection does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The option for input clock selection does not exist\n");
return -EINVAL;
} /* if(data[0]!=3) */
} /* elseif(data[0]==0||data[0]==1||data[0]==2) */
@@ -1335,7 +1024,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[2] = APCI1500_TIMER;
break;
default:
- printk("\nThis choice is not a timer nor a counter\n");
+ dev_warn(dev->hw_dev,
+ "This choice is not a timer nor a counter\n");
return -EINVAL;
} /* switch(data[2]) */
@@ -1348,139 +1038,110 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[4] = APCI1500_SINGLE;
break;
default:
- printk("\nThis option for single/continuous mode does not exist\n");
+ dev_warn(dev->hw_dev,
+ "This option for single/continuous mode does not exist\n");
return -EINVAL;
} /* switch(data[4]) */
i_TimerCounterMode = data[2] | data[4] | 7;
- /*************************/
/* Test the reload value */
- /*************************/
if ((data[3] >= 0) && (data[3] <= 65535)) {
if (data[7] == APCI1500_ENABLE
|| data[7] == APCI1500_DISABLE) {
- /************************************************/
/* Selects the mode register of timer/counter 1 */
- /************************************************/
outb(APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************/
/* Writes the new mode */
- /***********************/
outb(i_TimerCounterMode,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************************/
/* Selects the constant register of timer/counter 1 */
- /****************************************************/
outb(APCI1500_RW_CPT_TMR1_TIME_CST_LOW,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*************************/
/* Writes the low value */
- /*************************/
outb(data[3],
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************************/
/* Selects the constant register of timer/counter 1 */
- /****************************************************/
outb(APCI1500_RW_CPT_TMR1_TIME_CST_HIGH,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**************************/
/* Writes the high value */
- /**************************/
data[3] = data[3] >> 8;
outb(data[3],
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*********************************************/
/* Selects the master configuration register */
- /*********************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************/
/* Reads the register */
- /**********************/
i_MasterConfiguration =
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************************************/
/* Enables timer/counter 1 and triggers timer/counter 1 */
- /********************************************************/
i_MasterConfiguration =
i_MasterConfiguration | 0x40;
- /*********************************************/
/* Selects the master configuration register */
- /*********************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************/
/* Writes the new configuration */
- /********************************/
outb(i_MasterConfiguration,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************/
/* Selects the commands register of */
/* timer/counter 1 */
- /****************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************/
/* Disable timer/counter 1 */
- /***************************/
outb(0x0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************/
/* Selects the commands register of */
/* timer/counter 1 */
- /****************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************/
/* Trigger timer/counter 1 */
- /***************************/
outb(0x2,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
} /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
else {
- printk("\nError in selection of interrupt enable or disable\n");
+ dev_warn(dev->hw_dev,
+ "Error in selection of interrupt enable or disable\n");
return -EINVAL;
} /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
} /* if ((data[3]>= 0) && (data[3] <= 65535)) */
else {
- printk("\nError in selection of reload value\n");
+ dev_warn(dev->hw_dev,
+ "Error in selection of reload value\n");
return -EINVAL;
} /* else if ((data[3]>= 0) && (data[3] <= 65535)) */
i_TimerCounterWatchdogInterrupt = data[7];
@@ -1496,7 +1157,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[2] = APCI1500_TIMER;
break;
default:
- printk("\nThis choice is not a timer nor a counter\n");
+ dev_warn(dev->hw_dev,
+ "This choice is not a timer nor a counter\n");
return -EINVAL;
} /* switch(data[2]) */
@@ -1509,7 +1171,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[4] = APCI1500_SINGLE;
break;
default:
- printk("\nThis option for single/continuous mode does not exist\n");
+ dev_warn(dev->hw_dev,
+ "This option for single/continuous mode does not exist\n");
return -EINVAL;
} /* switch(data[4]) */
@@ -1522,7 +1185,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[5] = APCI1500_HARDWARE_TRIGGER;
break;
default:
- printk("\nThis choice for software or hardware trigger does not exist\n");
+ dev_warn(dev->hw_dev,
+ "This choice for software or hardware trigger does not exist\n");
return -EINVAL;
} /* switch(data[5]) */
@@ -1535,140 +1199,111 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[6] = APCI1500_HARDWARE_GATE;
break;
default:
- printk("\nThis choice for software or hardware gate does not exist\n");
+ dev_warn(dev->hw_dev,
+ "This choice for software or hardware gate does not exist\n");
return -EINVAL;
} /* switch(data[6]) */
i_TimerCounterMode = data[2] | data[4] | data[5] | data[6] | 7;
- /*************************/
/* Test the reload value */
- /*************************/
if ((data[3] >= 0) && (data[3] <= 65535)) {
if (data[7] == APCI1500_ENABLE
|| data[7] == APCI1500_DISABLE) {
- /************************************************/
/* Selects the mode register of timer/counter 2 */
- /************************************************/
outb(APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************/
/* Writes the new mode */
- /***********************/
outb(i_TimerCounterMode,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************************/
/* Selects the constant register of timer/counter 2 */
- /****************************************************/
outb(APCI1500_RW_CPT_TMR2_TIME_CST_LOW,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*************************/
/* Writes the low value */
- /*************************/
outb(data[3],
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************************/
/* Selects the constant register of timer/counter 2 */
- /****************************************************/
outb(APCI1500_RW_CPT_TMR2_TIME_CST_HIGH,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**************************/
/* Writes the high value */
- /**************************/
data[3] = data[3] >> 8;
outb(data[3],
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*********************************************/
/* Selects the master configuration register */
- /*********************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************/
/* Reads the register */
- /**********************/
i_MasterConfiguration =
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************************************/
/* Enables timer/counter 2 and triggers timer/counter 2 */
- /********************************************************/
i_MasterConfiguration =
i_MasterConfiguration | 0x20;
- /*********************************************/
/* Selects the master configuration register */
- /*********************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************/
/* Writes the new configuration */
- /********************************/
outb(i_MasterConfiguration,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************/
/* Selects the commands register of */
/* timer/counter 2 */
- /****************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************/
/* Disable timer/counter 2 */
- /***************************/
outb(0x0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************/
/* Selects the commands register of */
/* timer/counter 2 */
- /****************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************/
/* Trigger timer/counter 1 */
- /***************************/
outb(0x2,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
} /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
else {
- printk("\nError in selection of interrupt enable or disable\n");
+ dev_warn(dev->hw_dev,
+ "Error in selection of interrupt enable or disable\n");
return -EINVAL;
} /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
} /* if ((data[3]>= 0) && (data[3] <= 65535)) */
else {
- printk("\nError in selection of reload value\n");
+ dev_warn(dev->hw_dev,
+ "Error in selection of reload value\n");
return -EINVAL;
} /* else if ((data[3]>= 0) && (data[3] <= 65535)) */
i_TimerCounterWatchdogInterrupt = data[7];
@@ -1684,7 +1319,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[2] = APCI1500_WATCHDOG;
break;
default:
- printk("\nThis choice is not a watchdog nor a counter\n");
+ dev_warn(dev->hw_dev,
+ "This choice is not a watchdog nor a counter\n");
return -EINVAL;
} /* switch(data[2]) */
@@ -1697,7 +1333,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[4] = APCI1500_SINGLE;
break;
default:
- printk("\nThis option for single/continuous mode does not exist\n");
+ dev_warn(dev->hw_dev,
+ "This option for single/continuous mode does not exist\n");
return -EINVAL;
} /* switch(data[4]) */
@@ -1710,146 +1347,109 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
data[6] = APCI1500_HARDWARE_GATE;
break;
default:
- printk("\nThis choice for software or hardware gate does not exist\n");
+ dev_warn(dev->hw_dev,
+ "This choice for software or hardware gate does not exist\n");
return -EINVAL;
} /* switch(data[6]) */
- /*****************************/
/* Test if used for watchdog */
- /*****************************/
if (data[2] == APCI1500_WATCHDOG) {
- /*****************************/
/* - Enables the output line */
/* - Enables retrigger */
/* - Pulses output */
- /*****************************/
i_TimerCounterMode = data[2] | data[4] | 0x54;
} /* if (data[2] == APCI1500_WATCHDOG) */
else {
i_TimerCounterMode = data[2] | data[4] | data[6] | 7;
} /* elseif (data[2] == APCI1500_WATCHDOG) */
- /*************************/
/* Test the reload value */
- /*************************/
if ((data[3] >= 0) && (data[3] <= 65535)) {
if (data[7] == APCI1500_ENABLE
|| data[7] == APCI1500_DISABLE) {
- /************************************************/
/* Selects the mode register of watchdog/counter 3 */
- /************************************************/
outb(APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************/
/* Writes the new mode */
- /***********************/
outb(i_TimerCounterMode,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************************/
/* Selects the constant register of watchdog/counter 3 */
- /****************************************************/
outb(APCI1500_RW_CPT_TMR3_TIME_CST_LOW,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*************************/
/* Writes the low value */
- /*************************/
outb(data[3],
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /****************************************************/
/* Selects the constant register of watchdog/counter 3 */
- /****************************************************/
outb(APCI1500_RW_CPT_TMR3_TIME_CST_HIGH,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**************************/
/* Writes the high value */
- /**************************/
data[3] = data[3] >> 8;
outb(data[3],
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*********************************************/
/* Selects the master configuration register */
- /*********************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /**********************/
/* Reads the register */
- /**********************/
i_MasterConfiguration =
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************************************/
/* Enables watchdog/counter 3 and triggers watchdog/counter 3 */
- /********************************************************/
i_MasterConfiguration =
i_MasterConfiguration | 0x10;
- /*********************************************/
/* Selects the master configuration register */
- /*********************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************************/
/* Writes the new configuration */
- /********************************/
outb(i_MasterConfiguration,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /********************/
/* Test if COUNTER */
- /********************/
if (data[2] == APCI1500_COUNTER) {
- /*************************************/
/* Selects the command register of */
/* watchdog/counter 3 */
- /*************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************************/
/* Disable the watchdog/counter 3 and starts it */
- /*************************************************/
outb(0x0,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************/
/* Selects the command register of */
/* watchdog/counter 3 */
- /*************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************************/
/* Trigger the watchdog/counter 3 and starts it */
- /*************************************************/
outb(0x2,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -1858,12 +1458,14 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
} /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
else {
- printk("\nError in selection of interrupt enable or disable\n");
+ dev_warn(dev->hw_dev,
+ "Error in selection of interrupt enable or disable\n");
return -EINVAL;
} /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
} /* if ((data[3]>= 0) && (data[3] <= 65535)) */
else {
- printk("\nError in selection of reload value\n");
+ dev_warn(dev->hw_dev,
+ "Error in selection of reload value\n");
return -EINVAL;
} /* else if ((data[3]>= 0) && (data[3] <= 65535)) */
i_TimerCounterWatchdogInterrupt = data[7];
@@ -1871,44 +1473,25 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
break;
default:
- printk("\nThe specified counter\timer option does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified counter/timer option does not exist\n");
+ return -EINVAL;
} /* switch(data[1]) */
i_CounterLogic = data[2];
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_StartStopTriggerTimerCounterWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s,
-| struct comedi_insn *insn,unsigned int *data); |
-+----------------------------------------------------------------------------+
-| Task : Start / Stop or trigger the timer counter or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| struct comedi_subdevice *s, :pointer to subdevice structure
-| struct comedi_insn *insn :pointer to insn structure |
-| unsigned int *data : Data Pointer to read status |
-| data[0] : 0 Counter1/Timer1
-| 1 Counter2/Timer2
-| 2 Counter3/Watchdog
-| data[1] : 0 start
-| 1 stop
-| 2 Trigger
-| data[2] : 0 Counter
-| 1 Timer/Watchdog
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Start / Stop or trigger the timer counter or Watchdog
+ *
+ * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog
+ * data[1] 0 = Start, 1 = Stop, 2 = Trigger
+ * data[2] 0 = Counter, 1 = Timer/Watchdog
+ */
+static int apci1500_timer_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
int i_CommandAndStatusValue;
@@ -1924,13 +1507,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
else {
i_CommandAndStatusValue = 0xE4; /* disable the interrupt */
} /* elseif(i_TimerCounterWatchdogInterrupt==1) */
- /**************************/
/* Starts timer/counter 1 */
- /**************************/
i_TimerCounter1Enabled = 1;
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -1939,20 +1518,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_TimerCounter1Init==1) */
else {
- printk("\nCounter/Timer1 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Counter/Timer1 not configured\n");
return -EINVAL;
}
break;
case STOP:
- /**************************/
/* Stop timer/counter 1 */
- /**************************/
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -1965,23 +1541,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
case TRIGGER:
if (i_TimerCounter1Init == 1) {
if (i_TimerCounter1Enabled == 1) {
- /************************/
/* Set Trigger and gate */
- /************************/
i_CommandAndStatusValue = 0x6;
} /* if( i_TimerCounter1Enabled==1) */
else {
- /***************/
/* Set Trigger */
- /***************/
i_CommandAndStatusValue = 0x2;
} /* elseif(i_TimerCounter1Enabled==1) */
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -1990,13 +1560,15 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_TimerCounter1Init==1) */
else {
- printk("\nCounter/Timer1 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Counter/Timer1 not configured\n");
return -EINVAL;
}
break;
default:
- printk("\nThe specified option for start/stop/trigger does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified option for start/stop/trigger does not exist\n");
return -EINVAL;
} /* switch(data[1]) */
break;
@@ -2011,13 +1583,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
else {
i_CommandAndStatusValue = 0xE4; /* disable the interrupt */
} /* elseif(i_TimerCounterWatchdogInterrupt==1) */
- /**************************/
/* Starts timer/counter 2 */
- /**************************/
i_TimerCounter2Enabled = 1;
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2026,20 +1594,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_TimerCounter2Init==1) */
else {
- printk("\nCounter/Timer2 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Counter/Timer2 not configured\n");
return -EINVAL;
}
break;
case STOP:
- /**************************/
/* Stop timer/counter 2 */
- /**************************/
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2051,23 +1616,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
case TRIGGER:
if (i_TimerCounter2Init == 1) {
if (i_TimerCounter2Enabled == 1) {
- /************************/
/* Set Trigger and gate */
- /************************/
i_CommandAndStatusValue = 0x6;
} /* if( i_TimerCounter2Enabled==1) */
else {
- /***************/
/* Set Trigger */
- /***************/
i_CommandAndStatusValue = 0x2;
} /* elseif(i_TimerCounter2Enabled==1) */
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2076,12 +1635,14 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_TimerCounter2Init==1) */
else {
- printk("\nCounter/Timer2 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Counter/Timer2 not configured\n");
return -EINVAL;
}
break;
default:
- printk("\nThe specified option for start/stop/trigger does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified option for start/stop/trigger does not exist\n");
return -EINVAL;
} /* switch(data[1]) */
break;
@@ -2096,13 +1657,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
else {
i_CommandAndStatusValue = 0xE4; /* disable the interrupt */
} /* elseif(i_TimerCounterWatchdogInterrupt==1) */
- /**************************/
/* Starts Watchdog/counter 3 */
- /**************************/
i_WatchdogCounter3Enabled = 1;
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2112,20 +1669,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
} /* if( i_WatchdogCounter3init==1) */
else {
- printk("\nWatchdog/Counter3 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Watchdog/Counter3 not configured\n");
return -EINVAL;
}
break;
case STOP:
- /**************************/
/* Stop Watchdog/counter 3 */
- /**************************/
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2140,23 +1694,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
case 0: /* triggering counter 3 */
if (i_WatchdogCounter3Init == 1) {
if (i_WatchdogCounter3Enabled == 1) {
- /************************/
/* Set Trigger and gate */
- /************************/
i_CommandAndStatusValue = 0x6;
} /* if( i_WatchdogCounter3Enabled==1) */
else {
- /***************/
/* Set Trigger */
- /***************/
i_CommandAndStatusValue = 0x2;
} /* elseif(i_WatchdogCounter3Enabled==1) */
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2165,7 +1713,8 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_WatchdogCounter3Init==1) */
else {
- printk("\nCounter3 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Counter3 not configured\n");
return -EINVAL;
}
break;
@@ -2173,9 +1722,7 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
/* triggering Watchdog 3 */
if (i_WatchdogCounter3Init == 1) {
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2184,55 +1731,40 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_WatchdogCounter3Init==1) */
else {
- printk("\nWatchdog 3 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Watchdog 3 not configured\n");
return -EINVAL;
}
break;
default:
- printk("\nWrong choice of watchdog/counter3\n");
+ dev_warn(dev->hw_dev,
+ "Wrong choice of watchdog/counter3\n");
return -EINVAL;
} /* switch(data[2]) */
break;
default:
- printk("\nThe specified option for start/stop/trigger does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified option for start/stop/trigger does not exist\n");
return -EINVAL;
} /* switch(data[1]) */
break;
default:
- printk("\nThe specified choice for counter/watchdog/timer does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The specified choice for counter/watchdog/timer does not exist\n");
return -EINVAL;
} /* switch(data[0]) */
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_ReadCounterTimerWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
-| unsigned int *data); |
-+----------------------------------------------------------------------------+
-| Task : Read The Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| struct comedi_subdevice *s, :pointer to subdevice structure
-| struct comedi_insn *insn :pointer to insn structure |
-| unsigned int *data : Data Pointer to read status |
-| data[0] : 0 Counter1/Timer1
-| 1 Counter2/Timer2
-| 2 Counter3/Watchdog
-|
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Read The Watchdog
+ *
+ * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog
+ */
+static int apci1500_timer_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
int i_CommandAndStatusValue;
@@ -2242,23 +1774,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
/* Read counter/timer1 */
if (i_TimerCounter1Init == 1) {
if (i_TimerCounter1Enabled == 1) {
- /************************/
/* Set RCC and gate */
- /************************/
i_CommandAndStatusValue = 0xC;
} /* if( i_TimerCounter1Init==1) */
else {
- /***************/
/* Set RCC */
- /***************/
i_CommandAndStatusValue = 0x8;
} /* elseif(i_TimerCounter1Init==1) */
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2266,9 +1792,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************/
/* Selects the counter register (high) */
- /***************************************/
outb(APCI1500_R_CPT_TMR1_VALUE_HIGH,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2285,7 +1809,8 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_TimerCounter1Init==1) */
else {
- printk("\nTimer/Counter1 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Timer/Counter1 not configured\n");
return -EINVAL;
} /* elseif( i_TimerCounter1Init==1) */
break;
@@ -2293,23 +1818,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
/* Read counter/timer2 */
if (i_TimerCounter2Init == 1) {
if (i_TimerCounter2Enabled == 1) {
- /************************/
/* Set RCC and gate */
- /************************/
i_CommandAndStatusValue = 0xC;
} /* if( i_TimerCounter2Init==1) */
else {
- /***************/
/* Set RCC */
- /***************/
i_CommandAndStatusValue = 0x8;
} /* elseif(i_TimerCounter2Init==1) */
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2317,9 +1836,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************/
/* Selects the counter register (high) */
- /***************************************/
outb(APCI1500_R_CPT_TMR2_VALUE_HIGH,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2336,7 +1853,8 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_TimerCounter2Init==1) */
else {
- printk("\nTimer/Counter2 not configured\n");
+ dev_warn(dev->hw_dev,
+ "Timer/Counter2 not configured\n");
return -EINVAL;
} /* elseif( i_TimerCounter2Init==1) */
break;
@@ -2344,23 +1862,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
/* Read counter/watchdog2 */
if (i_WatchdogCounter3Init == 1) {
if (i_WatchdogCounter3Enabled == 1) {
- /************************/
/* Set RCC and gate */
- /************************/
i_CommandAndStatusValue = 0xC;
} /* if( i_TimerCounter2Init==1) */
else {
- /***************/
/* Set RCC */
- /***************/
i_CommandAndStatusValue = 0x8;
} /* elseif(i_WatchdogCounter3Init==1) */
- /********************************************/
/* Selects the commands and status register */
- /********************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2368,9 +1880,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************/
/* Selects the counter register (high) */
- /***************************************/
outb(APCI1500_R_CPT_TMR3_VALUE_HIGH,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2387,12 +1897,14 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
APCI1500_Z8536_CONTROL_REGISTER);
} /* if( i_WatchdogCounter3Init==1) */
else {
- printk("\nWatchdogCounter3 not configured\n");
+ dev_warn(dev->hw_dev,
+ "WatchdogCounter3 not configured\n");
return -EINVAL;
} /* elseif( i_WatchdogCounter3Init==1) */
break;
default:
- printk("\nThe choice of timer/counter/watchdog does not exist\n");
+ dev_warn(dev->hw_dev,
+ "The choice of timer/counter/watchdog does not exist\n");
return -EINVAL;
} /* switch(data[0]) */
@@ -2400,31 +1912,15 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_ReadInterruptMask |
-| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
-| unsigned int *data); |
-+----------------------------------------------------------------------------+
-| Task : Read the interrupt mask |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| struct comedi_subdevice *s, :pointer to subdevice structure
-| struct comedi_insn *insn :pointer to insn structure |
-| unsigned int *data : Data Pointer to read status |
-
-
-+----------------------------------------------------------------------------+
-| Output Parameters : -- data[0]:The interrupt mask value data[1]:Channel no
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Read the interrupt mask
+ *
+ * data[0] The interrupt mask value
+ * data[1] Channel Number
+ */
+static int apci1500_timer_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
data[0] = i_InterruptMask;
data[1] = i_InputChannel;
@@ -2433,31 +1929,12 @@ static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev,
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_ConfigureInterrupt |
-| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
-| unsigned int *data); |
-+----------------------------------------------------------------------------+
-| Task : Configures the interrupt registers |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| struct comedi_subdevice *s, :pointer to subdevice structure
-| struct comedi_insn *insn :pointer to insn structure |
-| unsigned int *data : Data Pointer |
-|
-
-+----------------------------------------------------------------------------+
-| Output Parameters : --
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures the interrupt registers
+ */
+static int apci1500_do_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ui_Status;
@@ -2474,140 +1951,101 @@ static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev,
i_Constant = 0x00;
} /* if{data[0]==0) */
else {
- printk("\nThe parameter passed to driver is in error for enabling the voltage interrupt\n");
+ dev_warn(dev->hw_dev,
+ "The parameter passed to driver is in error for enabling the voltage interrupt\n");
return -EINVAL;
} /* else if(data[0]==0) */
} /* elseif(data[0]==1) */
- /*****************************************************/
/* Selects the mode specification register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*********************************************/
/* Writes the new configuration (APCI1500_OR) */
- /*********************************************/
i_RegValue = (i_RegValue & 0xF9) | APCI1500_OR;
outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************/
/* Authorises the interrupt on the board */
- /*****************************************/
outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************************/
/* Selects the pattern polarity register of port B */
- /***************************************************/
outb(APCI1500_RW_PORT_B_PATTERN_POLARITY,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the pattern transition register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************************/
/* Selects the pattern mask register of port B */
- /***********************************************/
outb(APCI1500_RW_PORT_B_PATTERN_MASK,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of port A */
- /*****************************************************/
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of port A */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of port B */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of timer 1 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of timer 1 */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of timer 2 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of timer 2 */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of timer 3 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of timer 3 */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Authorizes the main interrupt on the board */
- /**********************************************/
outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /***************************/
/* Enables the PCI interrupt */
- /*****************************/
outl(0x3000, devpriv->i_IobaseAmcc + 0x38);
ui_Status = inl(devpriv->i_IobaseAmcc + 0x10);
ui_Status = inl(devpriv->i_IobaseAmcc + 0x38);
@@ -2616,24 +2054,7 @@ static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev,
return insn->n;
}
-/*
-+----------------------------------------------------------------------------+
-| Function Name : static void v_APCI1500_Interrupt |
-| (int irq , void *d) |
-+----------------------------------------------------------------------------+
-| Task : Interrupt handler |
-+----------------------------------------------------------------------------+
-| Input Parameters : int irq : irq number |
-| void *d : void pointer |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static void v_APCI1500_Interrupt(int irq, void *d)
+static void apci1500_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
@@ -2642,44 +2063,28 @@ static void v_APCI1500_Interrupt(int irq, void *d)
int i_RegValue = 0;
i_InterruptMask = 0;
- /***********************************/
/* Read the board interrupt status */
- /***********************************/
ui_InterruptStatus = inl(devpriv->i_IobaseAmcc + 0x38);
- /***************************************/
/* Test if board generated a interrupt */
- /***************************************/
if ((ui_InterruptStatus & 0x800000) == 0x800000) {
- /************************/
/* Disable all Interrupt */
- /************************/
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
/* outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */
- /**********************************************/
/* Disables the main interrupt on the board */
- /**********************************************/
/* outb(0x00,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */
- /*****************************************************/
/* Selects the command and status register of port A */
- /*****************************************************/
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue =
inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
if ((i_RegValue & 0x60) == 0x60) {
- /*****************************************************/
/* Selects the command and status register of port A */
- /*****************************************************/
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of port A */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue,
devpriv->iobase +
@@ -2693,9 +2098,7 @@ static void v_APCI1500_Interrupt(int irq, void *d)
inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***************************************************/
/* Selects the interrupt vector register of port A */
- /***************************************************/
outb(APCI1500_RW_PORT_A_INTERRUPT_CONTROL,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
@@ -2711,45 +2114,32 @@ static void v_APCI1500_Interrupt(int irq, void *d)
} /* elseif(i_Logic==APCI1500_OR_PRIORITY) */
} /* if ((i_RegValue & 0x60) == 0x60) */
- /*****************************************************/
/* Selects the command and status register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue =
inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
if ((i_RegValue & 0x60) == 0x60) {
- /*****************************************************/
/* Selects the command and status register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of port B */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- printk("\n\n\n");
- /****************/
/* Reads port B */
- /****************/
i_RegValue =
inb((unsigned int) devpriv->iobase +
APCI1500_Z8536_PORT_B);
i_RegValue = i_RegValue & 0xC0;
- /**************************************/
/* Tests if this is an external error */
- /**************************************/
if (i_RegValue) {
/* Disable the interrupt */
- /*****************************************************/
/* Selects the command and status register of port B */
- /*****************************************************/
outl(0x0, devpriv->i_IobaseAmcc + 0x38);
if (i_RegValue & 0x80) {
@@ -2767,46 +2157,34 @@ static void v_APCI1500_Interrupt(int irq, void *d)
} /* if (i_RegValue) */
} /* if ((i_RegValue & 0x60) == 0x60) */
- /*****************************************************/
/* Selects the command and status register of timer 1 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue =
inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
if ((i_RegValue & 0x60) == 0x60) {
- /*****************************************************/
/* Selects the command and status register of timer 1 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of timer 1 */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
i_InterruptMask = i_InterruptMask | 4;
} /* if ((i_RegValue & 0x60) == 0x60) */
- /*****************************************************/
/* Selects the command and status register of timer 2 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue =
inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
if ((i_RegValue & 0x60) == 0x60) {
- /*****************************************************/
/* Selects the command and status register of timer 2 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of timer 2 */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue,
devpriv->iobase +
@@ -2814,23 +2192,17 @@ static void v_APCI1500_Interrupt(int irq, void *d)
i_InterruptMask = i_InterruptMask | 8;
} /* if ((i_RegValue & 0x60) == 0x60) */
- /*****************************************************/
/* Selects the command and status register of timer 3 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_RegValue =
inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
if ((i_RegValue & 0x60) == 0x60) {
- /*****************************************************/
/* Selects the command and status register of timer 3 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- /***********************************/
/* Deletes the interrupt of timer 3 */
- /***********************************/
i_RegValue = (i_RegValue & 0x0F) | 0x20;
outb(i_RegValue,
devpriv->iobase +
@@ -2844,42 +2216,23 @@ static void v_APCI1500_Interrupt(int irq, void *d)
} /* if ((i_RegValue & 0x60) == 0x60) */
send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
- /***********************/
/* Enable all Interrupts */
- /***********************/
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /**********************************************/
/* Authorizes the main interrupt on the board */
- /**********************************************/
outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
} /* if ((ui_InterruptStatus & 0x800000) == 0x800000) */
else {
- printk("\nInterrupt from unknown source\n");
+ dev_warn(dev->hw_dev,
+ "Interrupt from unknown source\n");
} /* else if ((ui_InterruptStatus & 0x800000) == 0x800000) */
return;
}
-/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1500_Reset(struct comedi_device *dev) | |
-+----------------------------------------------------------------------------+
-| Task :resets all the registers |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1500_Reset(struct comedi_device *dev)
+static int apci1500_reset(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
int i_DummyRead = 0;
@@ -2898,9 +2251,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
i_TimerCounter2Enabled = 0;
i_WatchdogCounter3Enabled = 0;
- /******************/
/* Software reset */
- /******************/
i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
@@ -2908,16 +2259,12 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the master configuration control register */
- /*****************************************************/
outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the mode specification register of port A */
- /*****************************************************/
outb(APCI1500_RW_PORT_A_SPECIFICATION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
@@ -2949,9 +2296,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
/* Deletes the register */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the mode specification register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_SPECIFICATION,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
@@ -2981,9 +2326,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
/* Deletes the register */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the data path polarity register of port C */
- /*****************************************************/
outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* High level of port C means 1 */
@@ -2998,9 +2341,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes it */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************************/
/* Selects the command and status register of timer 1 */
- /******************************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes IP and IUS */
@@ -3010,9 +2351,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deactivates the interrupt management of timer 1 */
outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************************/
/* Selects the command and status register of timer 2 */
- /******************************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes IP and IUS */
@@ -3022,9 +2361,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deactivates Timer 2 interrupt management: */
outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /******************************************************/
/* Selects the command and status register of timer 3 */
- /******************************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes IP and IUS */
@@ -3034,71 +2371,43 @@ static int i_APCI1500_Reset(struct comedi_device *dev)
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deactivates interrupt management of timer 3: */
outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* Deletes all interrupts */
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
/* reset all the digital outputs */
outw(0x0, devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP);
-/*******************************/
/* Disable the board interrupt */
-/*******************************/
- /*************************************************/
/* Selects the master interrupt control register */
- /*************************************************/
outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/****************************/
/* Deactivates all interrupts */
-/******************************/
outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /*****************************************************/
/* Selects the command and status register of port A */
- /*****************************************************/
outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/****************************/
/* Deactivates all interrupts */
-/******************************/
outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/*****************************************************/
/* Selects the command and status register of port B */
- /*****************************************************/
outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/****************************/
/* Deactivates all interrupts */
-/******************************/
outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/*****************************************************/
/* Selects the command and status register of timer 1 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/****************************/
/* Deactivates all interrupts */
-/******************************/
outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/*****************************************************/
/* Selects the command and status register of timer 2 */
- /*****************************************************/
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/****************************/
/* Deactivates all interrupts */
-/******************************/
outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/*****************************************************/
/* Selects the command and status register of timer 3*/
-/*****************************************************/
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/****************************/
/* Deactivates all interrupts */
-/******************************/
outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
return 0;
}
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c
index 84668544f52..0ba5385226a 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c
@@ -1,74 +1,34 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
-
- ADDI-DATA GmbH
- Dieselstrasse 3
- D-77833 Ottersweier
- Tel: +19(0)7223/9493-0
- Fax: +49(0)7223/9493-92
- http://www.addi-data.com
- info@addi-data.com
-
-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.
-
-@endverbatim
-*/
/*
-
- +-----------------------------------------------------------------------+
- | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier |
- +-----------------------------------------------------------------------+
- | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com |
- | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com |
- +-------------------------------+---------------------------------------+
- | Project : APCI-1564 | Compiler : GCC |
- | Module name : hwdrv_apci1564.c| Version : 2.96 |
- +-------------------------------+---------------------------------------+
- | Project manager: Eric Stolz | Date : 02/12/2002 |
- +-------------------------------+---------------------------------------+
- | Description : Hardware Layer Access For APCI-1564 |
- +-----------------------------------------------------------------------+
- | UPDATES |
- +----------+-----------+------------------------------------------------+
- | Date | Author | Description of updates |
- +----------+-----------+------------------------------------------------+
- | | | |
- | | | |
- | | | |
- +----------+-----------+------------------------------------------------+
-*/
-
-/********* Definitions for APCI-1564 card *****/
+ * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
+ *
+ * ADDI-DATA GmbH
+ * Dieselstrasse 3
+ * D-77833 Ottersweier
+ * Tel: +19(0)7223/9493-0
+ * Fax: +49(0)7223/9493-92
+ * http://www.addi-data.com
+ * info@addi-data.com
+ *
+ * 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.
+ *
+ */
+
+#include "../addi_watchdog.h"
#define APCI1564_ADDRESS_RANGE 128
-/* DIGITAL INPUT-OUTPUT DEFINE */
-/* Input defines */
-#define APCI1564_DIGITAL_IP 0x04
-#define APCI1564_DIGITAL_IP_INTERRUPT_MODE1 4
-#define APCI1564_DIGITAL_IP_INTERRUPT_MODE2 8
-#define APCI1564_DIGITAL_IP_IRQ 16
-
-/* Output defines */
-#define APCI1564_DIGITAL_OP 0x18
-#define APCI1564_DIGITAL_OP_RW 0
-#define APCI1564_DIGITAL_OP_INTERRUPT 4
-#define APCI1564_DIGITAL_OP_IRQ 12
-
/* Digital Input IRQ Function Selection */
#define ADDIDATA_OR 0
#define ADDIDATA_AND 1
-/* Digital Input Interrupt Status */
-#define APCI1564_DIGITAL_IP_INTERRUPT_STATUS 12
-
-/* Digital Output Interrupt Status */
-#define APCI1564_DIGITAL_OP_INTERRUPT_STATUS 8
-
/* Digital Input Interrupt Enable Disable. */
#define APCI1564_DIGITAL_IP_INTERRUPT_ENABLE 0x4
#define APCI1564_DIGITAL_IP_INTERRUPT_DISABLE 0xfffffffb
@@ -80,143 +40,105 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
#define APCI1564_DIGITAL_OP_CC_INTERRUPT_DISABLE 0xfffffffd
/* TIMER COUNTER WATCHDOG DEFINES */
-
#define ADDIDATA_TIMER 0
#define ADDIDATA_COUNTER 1
#define ADDIDATA_WATCHDOG 2
-#define APCI1564_DIGITAL_OP_WATCHDOG 0x28
-#define APCI1564_TIMER 0x48
-#define APCI1564_COUNTER1 0x0
-#define APCI1564_COUNTER2 0x20
-#define APCI1564_COUNTER3 0x40
-#define APCI1564_COUNTER4 0x60
-#define APCI1564_TCW_SYNC_ENABLEDISABLE 0
-#define APCI1564_TCW_RELOAD_VALUE 4
-#define APCI1564_TCW_TIMEBASE 8
-#define APCI1564_TCW_PROG 12
-#define APCI1564_TCW_TRIG_STATUS 16
-#define APCI1564_TCW_IRQ 20
-#define APCI1564_TCW_WARN_TIMEVAL 24
-#define APCI1564_TCW_WARN_TIMEBASE 28
+#define APCI1564_COUNTER1 0
+#define APCI1564_COUNTER2 1
+#define APCI1564_COUNTER3 2
+#define APCI1564_COUNTER4 3
+
+/*
+ * devpriv->i_IobaseAmcc Register Map
+ */
+#define APCI1564_DI_REG 0x04
+#define APCI1564_DI_INT_MODE1_REG 0x08
+#define APCI1564_DI_INT_MODE2_REG 0x0c
+#define APCI1564_DI_INT_STATUS_REG 0x10
+#define APCI1564_DI_IRQ_REG 0x14
+#define APCI1564_DO_REG 0x18
+#define APCI1564_DO_INT_CTRL_REG 0x1c
+#define APCI1564_DO_INT_STATUS_REG 0x20
+#define APCI1564_DO_IRQ_REG 0x24
+#define APCI1564_WDOG_REG 0x28
+#define APCI1564_WDOG_RELOAD_REG 0x2c
+#define APCI1564_WDOG_TIMEBASE_REG 0x30
+#define APCI1564_WDOG_CTRL_REG 0x34
+#define APCI1564_WDOG_STATUS_REG 0x38
+#define APCI1564_WDOG_IRQ_REG 0x3c
+#define APCI1564_WDOG_WARN_TIMEVAL_REG 0x40
+#define APCI1564_WDOG_WARN_TIMEBASE_REG 0x44
+#define APCI1564_TIMER_REG 0x48
+#define APCI1564_TIMER_RELOAD_REG 0x4c
+#define APCI1564_TIMER_TIMEBASE_REG 0x50
+#define APCI1564_TIMER_CTRL_REG 0x54
+#define APCI1564_TIMER_STATUS_REG 0x58
+#define APCI1564_TIMER_IRQ_REG 0x5c
+#define APCI1564_TIMER_WARN_TIMEVAL_REG 0x60
+#define APCI1564_TIMER_WARN_TIMEBASE_REG 0x64
+
+/*
+ * dev>iobase Register Map
+ */
+#define APCI1564_TCW_REG(x) (0x00 + ((x) * 0x20))
+#define APCI1564_TCW_RELOAD_REG(x) (0x04 + ((x) * 0x20))
+#define APCI1564_TCW_TIMEBASE_REG(x) (0x08 + ((x) * 0x20))
+#define APCI1564_TCW_CTRL_REG(x) (0x0c + ((x) * 0x20))
+#define APCI1564_TCW_STATUS_REG(x) (0x10 + ((x) * 0x20))
+#define APCI1564_TCW_IRQ_REG(x) (0x14 + ((x) * 0x20))
+#define APCI1564_TCW_WARN_TIMEVAL_REG(x) (0x18 + ((x) * 0x20))
+#define APCI1564_TCW_WARN_TIMEBASE_REG(x) (0x1c + ((x) * 0x20))
/* Global variables */
-static unsigned int ui_InterruptStatus_1564 = 0;
+static unsigned int ui_InterruptStatus_1564;
static unsigned int ui_InterruptData, ui_Type;
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_ConfigDigitalInput |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Configures the digital input Subdevice |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[0] : 1 Enable Digital Input Interrupt |
-| 0 Disable Digital Input Interrupt |
-| data[1] : 0 ADDIDATA Interrupt OR LOGIC |
-| : 1 ADDIDATA Interrupt AND LOGIC |
-| data[2] : Interrupt mask for the mode 1 |
-| data[3] : Interrupt mask for the mode 2 |
-| |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1564_ConfigDigitalInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures the digital input Subdevice
+ *
+ * data[0] 1 = Enable interrupt, 0 = Disable interrupt
+ * data[1] 0 = ADDIDATA Interrupt OR LOGIC, 1 = ADDIDATA Interrupt AND LOGIC
+ * data[2] Interrupt mask for the mode 1
+ * data[3] Interrupt mask for the mode 2
+ */
+static int apci1564_di_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
devpriv->tsk_Current = current;
- /*******************************/
+
/* Set the digital input logic */
- /*******************************/
if (data[0] == ADDIDATA_ENABLE) {
data[2] = data[2] << 4;
data[3] = data[3] << 4;
- outl(data[2],
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_INTERRUPT_MODE1);
- outl(data[3],
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_INTERRUPT_MODE2);
- if (data[1] == ADDIDATA_OR) {
- outl(0x4,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ);
- } /* if (data[1] == ADDIDATA_OR) */
- else {
- outl(0x6,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ);
- } /* else if (data[1] == ADDIDATA_OR) */
- } /* if (data[0] == ADDIDATA_ENABLE) */
- else {
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_INTERRUPT_MODE1);
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_INTERRUPT_MODE2);
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ);
- } /* else if (data[0] == ADDIDATA_ENABLE) */
-
- return insn->n;
-}
-
-static int apci1564_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
-
- data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP);
+ outl(data[2], devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG);
+ outl(data[3], devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG);
+ if (data[1] == ADDIDATA_OR)
+ outl(0x4, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
+ else
+ outl(0x6, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
+ } else {
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
+ }
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_ConfigDigitalOutput |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Configures The Digital Output Subdevice. |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[1] : 1 Enable VCC Interrupt |
-| 0 Disable VCC Interrupt |
-| data[2] : 1 Enable CC Interrupt |
-| 0 Disable CC Interrupt |
-| |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Configures The Digital Output Subdevice.
+ *
+ * data[1] 0 = Disable VCC Interrupt, 1 = Enable VCC Interrupt
+ * data[2] 0 = Disable CC Interrupt, 1 = Enable CC Interrupt
+ */
+static int apci1564_do_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ul_Command = 0;
@@ -225,90 +147,46 @@ static int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev,
comedi_error(dev,
"Not a valid Data !!! ,Data should be 1 or 0\n");
return -EINVAL;
- } /* if ((data[0]!=0) && (data[0]!=1)) */
- if (data[0]) {
+ }
+
+ if (data[0])
devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE;
- } /* if (data[0]) */
- else {
+ else
devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE;
- } /* else if (data[0]) */
- if (data[1] == ADDIDATA_ENABLE) {
+
+ if (data[1] == ADDIDATA_ENABLE)
ul_Command = ul_Command | 0x1;
- } /* if (data[1] == ADDIDATA_ENABLE) */
- else {
+ else
ul_Command = ul_Command & 0xFFFFFFFE;
- } /* else if (data[1] == ADDIDATA_ENABLE) */
- if (data[2] == ADDIDATA_ENABLE) {
+
+ if (data[2] == ADDIDATA_ENABLE)
ul_Command = ul_Command | 0x2;
- } /* if (data[2] == ADDIDATA_ENABLE) */
- else {
+ else
ul_Command = ul_Command & 0xFFFFFFFD;
- } /* else if (data[2] == ADDIDATA_ENABLE) */
- outl(ul_Command,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_INTERRUPT);
- ui_InterruptData =
- inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_INTERRUPT);
+
+ outl(ul_Command, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG);
+ ui_InterruptData = inl(devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG);
devpriv->tsk_Current = current;
return insn->n;
}
-static int apci1564_do_insn_bits(struct comedi_device *dev,
+/*
+ * Configures The Timer, Counter or Watchdog
+ *
+ * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog
+ * data[1] 1 = Enable Interrupt, 0 = Disable Interrupt
+ * data[2] Time Unit
+ * data[3] Reload Value
+ * data[4] Timer Mode
+ * data[5] Timer Counter Watchdog Number
+ * data[6] Counter Direction
+ */
+static int apci1564_timer_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
struct addi_private *devpriv = dev->private;
-
- s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_RW);
-
- if (comedi_dio_update_state(s, data))
- outl(s->state, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_RW);
-
- data[1] = s->state;
-
- return insn->n;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_ConfigTimerCounterWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Configures The Timer , Counter or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[0] : 0 Configure As Timer |
-| 1 Configure As Counter |
-| 2 Configure As Watchdog |
-| data[1] : 1 Enable Interrupt |
-| 0 Disable Interrupt |
-| data[2] : Time Unit |
-| data[3] : Reload Value |
-| data[4] : Timer Mode |
-| data[5] : Timer Counter Watchdog Number|
- data[6] : Counter Direction
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct addi_private *devpriv = dev->private;
unsigned int ul_Command1 = 0;
devpriv->tsk_Current = current;
@@ -316,89 +194,59 @@ static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev,
devpriv->b_TimerSelectMode = ADDIDATA_WATCHDOG;
/* Disable the watchdog */
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_PROG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG);
/* Loading the Reload value */
- outl(data[3],
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_RELOAD_VALUE);
- } /* if (data[0]==ADDIDATA_WATCHDOG) */
- else if (data[0] == ADDIDATA_TIMER) {
+ outl(data[3], devpriv->i_IobaseAmcc + APCI1564_WDOG_RELOAD_REG);
+ } else if (data[0] == ADDIDATA_TIMER) {
/* First Stop The Timer */
- ul_Command1 =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
+ ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
- outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Stop The Timer */
+ /* Stop The Timer */
+ outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
devpriv->b_TimerSelectMode = ADDIDATA_TIMER;
if (data[1] == 1) {
- outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ);
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_IRQ);
- outl(0x0,
- devpriv->i_IobaseAmcc +
- APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_IRQ);
+ /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */
+ outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_IRQ_REG);
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER1 +
- APCI1564_TCW_IRQ);
+ dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER2 +
- APCI1564_TCW_IRQ);
+ dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER3 +
- APCI1564_TCW_IRQ);
+ dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER4 +
- APCI1564_TCW_IRQ);
- } /* if (data[1]==1) */
- else {
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* disable Timer interrupt */
- } /* else if (data[1]==1) */
+ dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4));
+ } else {
+ /* disable Timer interrupt */
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ }
/* Loading Timebase */
-
- outl(data[2],
- devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_TIMEBASE);
+ outl(data[2], devpriv->i_IobaseAmcc + APCI1564_TIMER_TIMEBASE_REG);
/* Loading the Reload value */
- outl(data[3],
- devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_RELOAD_VALUE);
+ outl(data[3], devpriv->i_IobaseAmcc + APCI1564_TIMER_RELOAD_REG);
- ul_Command1 =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
- ul_Command1 =
- (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL;
- outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* mode 2 */
- } /* else if (data[0]==ADDIDATA_TIMER) */
- else if (data[0] == ADDIDATA_COUNTER) {
+ ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ ul_Command1 = (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL;
+ /* mode 2 */
+ outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ } else if (data[0] == ADDIDATA_COUNTER) {
devpriv->b_TimerSelectMode = ADDIDATA_COUNTER;
devpriv->b_ModeSelectRegister = data[5];
/* First Stop The Counter */
- ul_Command1 =
- inl(devpriv->iobase + ((data[5] - 1) * 0x20) +
- APCI1564_TCW_PROG);
+ ul_Command1 = inl(dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
- outl(ul_Command1, devpriv->iobase + ((data[5] - 1) * 0x20) + APCI1564_TCW_PROG); /* Stop The Timer */
+ /* Stop The Timer */
+ outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
- /************************/
/* Set the reload value */
- /************************/
- outl(data[3],
- devpriv->iobase + ((data[5] - 1) * 0x20) +
- APCI1564_TCW_RELOAD_VALUE);
+ outl(data[3], dev->iobase + APCI1564_TCW_RELOAD_REG(data[5] - 1));
- /******************************/
/* Set the mode : */
/* - Disable the hardware */
/* - Disable the counter mode */
@@ -406,65 +254,36 @@ static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev,
/* - Disable the reset */
/* - Disable the timer mode */
/* - Enable the counter mode */
- /******************************/
+
ul_Command1 =
(ul_Command1 & 0xFFFC19E2UL) | 0x80000UL |
(unsigned int) ((unsigned int) data[4] << 16UL);
- outl(ul_Command1,
- devpriv->iobase + ((data[5] - 1) * 0x20) +
- APCI1564_TCW_PROG);
+ outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
/* Enable or Disable Interrupt */
ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1);
- outl(ul_Command1,
- devpriv->iobase + ((data[5] - 1) * 0x20) +
- APCI1564_TCW_PROG);
+ outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
- /*****************************/
/* Set the Up/Down selection */
- /*****************************/
ul_Command1 = (ul_Command1 & 0xFFFBF9FFUL) | (data[6] << 18);
- outl(ul_Command1,
- devpriv->iobase + ((data[5] - 1) * 0x20) +
- APCI1564_TCW_PROG);
- } /* else if (data[0]==ADDIDATA_COUNTER) */
- else {
- printk(" Invalid subdevice.");
- } /* else if (data[0]==ADDIDATA_WATCHDOG) */
+ outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
+ } else {
+ dev_err(dev->class_dev, "Invalid subdevice.\n");
+ }
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_StartStopWriteTimerCounterWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Start / Stop The Selected Timer , Counter or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-| data[0] : 0 Timer |
-| 1 Counter |
-| 2 Watchdog | | data[1] : 1 Start |
-| 0 Stop |
-| 2 Trigger |
-| Clear (Only Counter) |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Start / Stop The Selected Timer, Counter or Watchdog
+ *
+ * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog
+ * data[1] 0 = Stop, 1 = Start, 2 = Trigger Clear (Only Counter)
+ */
+static int apci1564_timer_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ul_Command1 = 0;
@@ -472,203 +291,121 @@ static int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *d
if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
switch (data[1]) {
case 0: /* stop the watchdog */
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + APCI1564_TCW_PROG); /* disable the watchdog */
+ /* disable the watchdog */
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG);
break;
case 1: /* start the watchdog */
- outl(0x0001,
- devpriv->i_IobaseAmcc +
- APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_PROG);
+ outl(0x0001, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG);
break;
case 2: /* Software trigger */
- outl(0x0201,
- devpriv->i_IobaseAmcc +
- APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_PROG);
+ outl(0x0201, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG);
break;
default:
- printk("\nSpecified functionality does not exist\n");
+ dev_err(dev->class_dev, "Specified functionality does not exist.\n");
return -EINVAL;
- } /* switch (data[1]) */
- } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */
+ }
+ }
if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) {
if (data[1] == 1) {
- ul_Command1 =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
+ ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL;
/* Enable the Timer */
- outl(ul_Command1,
- devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
- } /* if (data[1]==1) */
- else if (data[1] == 0) {
+ outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ } else if (data[1] == 0) {
/* Stop The Timer */
- ul_Command1 =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
+ ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
- outl(ul_Command1,
- devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
- } /* else if(data[1]==0) */
- } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */
+ outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ }
+ }
if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) {
ul_Command1 =
- inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister -
- 1) * 0x20) + APCI1564_TCW_PROG);
+ inl(dev->iobase +
+ APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1));
if (data[1] == 1) {
/* Start the Counter subdevice */
ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL;
- } /* if (data[1] == 1) */
- else if (data[1] == 0) {
+ } else if (data[1] == 0) {
/* Stops the Counter subdevice */
ul_Command1 = 0;
- } /* else if (data[1] == 0) */
- else if (data[1] == 2) {
+ } else if (data[1] == 2) {
/* Clears the Counter subdevice */
ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400;
- } /* else if (data[1] == 3) */
- outl(ul_Command1,
- devpriv->iobase + ((devpriv->b_ModeSelectRegister -
- 1) * 0x20) + APCI1564_TCW_PROG);
- } /* if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) */
+ }
+ outl(ul_Command1, dev->iobase +
+ APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1));
+ }
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_ReadTimerCounterWatchdog |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task : Read The Selected Timer , Counter or Watchdog |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev : Driver handle |
-| unsigned int *data : Data Pointer contains |
-| configuration parameters as below |
-| |
-
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Read The Selected Timer, Counter or Watchdog
+ */
+static int apci1564_timer_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ul_Command1 = 0;
if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
/* Stores the status of the Watchdog */
- data[0] =
- inl(devpriv->i_IobaseAmcc +
- APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_TRIG_STATUS) & 0x1;
- data[1] =
- inl(devpriv->i_IobaseAmcc +
- APCI1564_DIGITAL_OP_WATCHDOG);
- } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */
- else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) {
+ data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_WDOG_STATUS_REG) & 0x1;
+ data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_WDOG_REG);
+ } else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) {
/* Stores the status of the Timer */
- data[0] =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_TRIG_STATUS) & 0x1;
+ data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_STATUS_REG) & 0x1;
/* Stores the Actual value of the Timer */
- data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER);
- } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */
- else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) {
+ data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_REG);
+ } else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) {
/* Read the Counter Actual Value. */
data[0] =
- inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister -
- 1) * 0x20) +
- APCI1564_TCW_SYNC_ENABLEDISABLE);
+ inl(dev->iobase +
+ APCI1564_TCW_REG(devpriv->b_ModeSelectRegister - 1));
ul_Command1 =
- inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister -
- 1) * 0x20) + APCI1564_TCW_TRIG_STATUS);
+ inl(dev->iobase +
+ APCI1564_TCW_STATUS_REG(devpriv->b_ModeSelectRegister - 1));
- /***********************************/
/* Get the software trigger status */
- /***********************************/
data[1] = (unsigned char) ((ul_Command1 >> 1) & 1);
- /***********************************/
/* Get the hardware trigger status */
- /***********************************/
data[2] = (unsigned char) ((ul_Command1 >> 2) & 1);
- /*********************************/
/* Get the software clear status */
- /*********************************/
data[3] = (unsigned char) ((ul_Command1 >> 3) & 1);
- /***************************/
/* Get the overflow status */
- /***************************/
data[4] = (unsigned char) ((ul_Command1 >> 0) & 1);
- } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) */
- else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER)
+ } else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER)
&& (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG)
&& (devpriv->b_TimerSelectMode != ADDIDATA_COUNTER)) {
- printk("\n Invalid Subdevice !!!\n");
- } /* else if ((devpriv->b_TimerSelectMode!=ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode!=ADDIDATA_WATCHDOG)&& (devpriv->b_TimerSelectMode!=ADDIDATA_COUNTER)) */
+ dev_err(dev->class_dev, "Invalid Subdevice!\n");
+ }
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_ReadInterruptStatus |
-| (struct comedi_device *dev,struct comedi_subdevice *s, |
-| struct comedi_insn *insn,unsigned int *data) |
-+----------------------------------------------------------------------------+
-| Task :Reads the interrupt status register |
-+----------------------------------------------------------------------------+
-| Input Parameters : |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : |
-| |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1564_ReadInterruptStatus(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ * Reads the interrupt status register
+ */
+static int apci1564_do_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
*data = ui_Type;
return insn->n;
}
/*
-+----------------------------------------------------------------------------+
-| Function Name : static void v_APCI1564_Interrupt |
-| (int irq , void *d) |
-+----------------------------------------------------------------------------+
-| Task : Interrupt handler for the interruptible digital inputs |
-+----------------------------------------------------------------------------+
-| Input Parameters : int irq : irq number |
-| void *d : void pointer |
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : TRUE : No error occur |
-| : FALSE : Error occur. Return the error |
-| |
-+----------------------------------------------------------------------------+
-*/
-static void v_APCI1564_Interrupt(int irq, void *d)
+ * Interrupt handler for the interruptible digital inputs
+ */
+static void apci1564_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct addi_private *devpriv = dev->private;
@@ -677,79 +414,63 @@ static void v_APCI1564_Interrupt(int irq, void *d)
unsigned int ui_C1, ui_C2, ui_C3, ui_C4;
unsigned int ul_Command2 = 0;
- ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ) & 0x01;
- ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_IRQ) & 0x01;
- ui_Timer =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_IRQ) & 0x01;
- ui_C1 = inl(devpriv->iobase + APCI1564_COUNTER1 +
- APCI1564_TCW_IRQ) & 0x1;
- ui_C2 = inl(devpriv->iobase + APCI1564_COUNTER2 +
- APCI1564_TCW_IRQ) & 0x1;
- ui_C3 = inl(devpriv->iobase + APCI1564_COUNTER3 +
- APCI1564_TCW_IRQ) & 0x1;
- ui_C4 = inl(devpriv->iobase + APCI1564_COUNTER4 +
- APCI1564_TCW_IRQ) & 0x1;
+ ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG) & 0x01;
+ ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG) & 0x01;
+ ui_Timer = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_IRQ_REG) & 0x01;
+ ui_C1 =
+ inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)) & 0x1;
+ ui_C2 =
+ inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)) & 0x1;
+ ui_C3 =
+ inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)) & 0x1;
+ ui_C4 =
+ inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)) & 0x1;
if (ui_DI == 0 && ui_DO == 0 && ui_Timer == 0 && ui_C1 == 0
&& ui_C2 == 0 && ui_C3 == 0 && ui_C4 == 0) {
- printk("\nInterrupt from unknown source\n");
- } /* if(ui_DI==0 && ui_DO==0 && ui_Timer==0 && ui_C1==0 && ui_C2==0 && ui_C3==0 && ui_C4==0) */
+ dev_err(dev->class_dev, "Interrupt from unknown source.\n");
+ }
if (ui_DI == 1) {
- ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ);
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_IRQ);
+ ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
ui_InterruptStatus_1564 =
- inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
- APCI1564_DIGITAL_IP_INTERRUPT_STATUS);
+ inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG);
ui_InterruptStatus_1564 = ui_InterruptStatus_1564 & 0X000FFFF0;
- send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
- outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ); /* enable the interrupt */
+ /* send signal to the sample */
+ send_sig(SIGIO, devpriv->tsk_Current, 0);
+ /* enable the interrupt */
+ outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
return;
}
if (ui_DO == 1) {
- /* Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt. */
- ui_Type =
- inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_INTERRUPT_STATUS) & 0x3;
+ /* Check for Digital Output interrupt Type */
+ /* 1: VCC interrupt */
+ /* 2: CC interrupt */
+ ui_Type = inl(devpriv->i_IobaseAmcc + APCI1564_DO_INT_STATUS_REG) & 0x3;
/* Disable the Interrupt */
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
- APCI1564_DIGITAL_OP_INTERRUPT);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG);
/* Sends signal to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
-
- } /* if (ui_DO) */
+ }
if (ui_Timer == 1) {
devpriv->b_TimerSelectMode = ADDIDATA_TIMER;
if (devpriv->b_TimerSelectMode) {
/* Disable Timer Interrupt */
- ul_Command2 =
- inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
+ ul_Command2 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
/* Send a signal to from kernel to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
/* Enable Timer Interrupt */
- outl(ul_Command2,
- devpriv->i_IobaseAmcc + APCI1564_TIMER +
- APCI1564_TCW_PROG);
+ outl(ul_Command2, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
}
- }/* if (ui_Timer == 1) */
-
+ }
if (ui_C1 == 1) {
devpriv->b_TimerSelectMode = ADDIDATA_COUNTER;
@@ -757,21 +478,18 @@ static void v_APCI1564_Interrupt(int irq, void *d)
/* Disable Counter Interrupt */
ul_Command2 =
- inl(devpriv->iobase + APCI1564_COUNTER1 +
- APCI1564_TCW_PROG);
+ inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER1 +
- APCI1564_TCW_PROG);
+ dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
/* Send a signal to from kernel to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
/* Enable Counter Interrupt */
outl(ul_Command2,
- devpriv->iobase + APCI1564_COUNTER1 +
- APCI1564_TCW_PROG);
+ dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
}
- } /* if (ui_C1 == 1) */
+ }
if (ui_C2 == 1) {
devpriv->b_TimerSelectMode = ADDIDATA_COUNTER;
@@ -779,21 +497,18 @@ static void v_APCI1564_Interrupt(int irq, void *d)
/* Disable Counter Interrupt */
ul_Command2 =
- inl(devpriv->iobase + APCI1564_COUNTER2 +
- APCI1564_TCW_PROG);
+ inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER2 +
- APCI1564_TCW_PROG);
+ dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
/* Send a signal to from kernel to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
/* Enable Counter Interrupt */
outl(ul_Command2,
- devpriv->iobase + APCI1564_COUNTER2 +
- APCI1564_TCW_PROG);
+ dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
}
- } /* if ((ui_C2 == 1) */
+ }
if (ui_C3 == 1) {
devpriv->b_TimerSelectMode = ADDIDATA_COUNTER;
@@ -801,21 +516,18 @@ static void v_APCI1564_Interrupt(int irq, void *d)
/* Disable Counter Interrupt */
ul_Command2 =
- inl(devpriv->iobase + APCI1564_COUNTER3 +
- APCI1564_TCW_PROG);
+ inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER3 +
- APCI1564_TCW_PROG);
+ dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
/* Send a signal to from kernel to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
/* Enable Counter Interrupt */
outl(ul_Command2,
- devpriv->iobase + APCI1564_COUNTER3 +
- APCI1564_TCW_PROG);
+ dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
}
- } /* if ((ui_C3 == 1) */
+ }
if (ui_C4 == 1) {
devpriv->b_TimerSelectMode = ADDIDATA_COUNTER;
@@ -823,60 +535,17 @@ static void v_APCI1564_Interrupt(int irq, void *d)
/* Disable Counter Interrupt */
ul_Command2 =
- inl(devpriv->iobase + APCI1564_COUNTER4 +
- APCI1564_TCW_PROG);
+ inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
outl(0x0,
- devpriv->iobase + APCI1564_COUNTER4 +
- APCI1564_TCW_PROG);
+ dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
/* Send a signal to from kernel to user space */
send_sig(SIGIO, devpriv->tsk_Current, 0);
/* Enable Counter Interrupt */
outl(ul_Command2,
- devpriv->iobase + APCI1564_COUNTER4 +
- APCI1564_TCW_PROG);
+ dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
}
- } /* if (ui_C4 == 1) */
+ }
return;
}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name : int i_APCI1564_Reset(struct comedi_device *dev) | |
-+----------------------------------------------------------------------------+
-| Task :resets all the registers |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev
-+----------------------------------------------------------------------------+
-| Output Parameters : -- |
-+----------------------------------------------------------------------------+
-| Return Value : |
-| |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1564_Reset(struct comedi_device *dev)
-{
- struct addi_private *devpriv = dev->private;
-
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_IRQ); /* disable the interrupts */
- inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_STATUS); /* Reset the interrupt status register */
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE1); /* Disable the and/or interrupt */
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE2);
- devpriv->b_DigitalOutputRegister = 0;
- ui_Type = 0;
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP); /* Resets the output channels */
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_INTERRUPT); /* Disables the interrupt. */
- outl(0x0,
- devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG +
- APCI1564_TCW_RELOAD_VALUE);
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER);
- outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG);
-
- outl(0x0, devpriv->iobase + APCI1564_COUNTER1 + APCI1564_TCW_PROG);
- outl(0x0, devpriv->iobase + APCI1564_COUNTER2 + APCI1564_TCW_PROG);
- outl(0x0, devpriv->iobase + APCI1564_COUNTER3 + APCI1564_TCW_PROG);
- outl(0x0, devpriv->iobase + APCI1564_COUNTER4 + APCI1564_TCW_PROG);
- return 0;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
index 3c9eec84f0e..764c8f17f8f 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
@@ -248,10 +248,10 @@ static const struct comedi_lrange range_apci3120_ao = {
+----------------------------------------------------------------------------+
*/
-static int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3120_ai_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
const struct addi_board *this_board = comedi_board(dev);
struct addi_private *devpriv = dev->private;
@@ -304,11 +304,11 @@ static int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,
* If the last argument of function "check"is 1 then it only checks
* the channel list is ok or not.
*/
-static int i_APCI3120_SetupChannelList(struct comedi_device *dev,
- struct comedi_subdevice *s,
- int n_chan,
- unsigned int *chanlist,
- char check)
+static int apci3120_setup_chan_list(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ int n_chan,
+ unsigned int *chanlist,
+ char check)
{
struct addi_private *devpriv = dev->private;
unsigned int i; /* , differencial=0, bipolar=0; */
@@ -358,10 +358,10 @@ static int i_APCI3120_SetupChannelList(struct comedi_device *dev,
* as per configured if no conversion time is set uses default
* conversion time 10 microsec.
*/
-static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3120_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
const struct addi_board *this_board = comedi_board(dev);
struct addi_private *devpriv = dev->private;
@@ -417,10 +417,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev,
inw(devpriv->iobase + APCI3120_RESET_FIFO);
/* Initialize the sequence array */
-
- /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */
-
- if (!i_APCI3120_SetupChannelList(dev, s, 1,
+ if (!apci3120_setup_chan_list(dev, s, 1,
&insn->chanspec, 0))
return -EINVAL;
@@ -512,7 +509,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev,
outw(devpriv->us_OutputRegister,
devpriv->iobase + APCI3120_WR_ADDRESS);
- if (!i_APCI3120_SetupChannelList(dev, s,
+ if (!apci3120_setup_chan_list(dev, s,
devpriv->ui_AiNbrofChannels,
devpriv->ui_AiChannelList, 0))
return -EINVAL;
@@ -606,17 +603,16 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev,
}
-static int i_APCI3120_Reset(struct comedi_device *dev)
+static int apci3120_reset(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
unsigned int i;
unsigned short us_TmpValue;
- devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+ devpriv->ai_running = 0;
devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
devpriv->b_InterruptMode = APCI3120_EOC_MODE;
devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */
- devpriv->b_OutputMemoryStatus = 0;
/* variables used in timer subdevice */
devpriv->b_Timer2Mode = 0;
@@ -663,7 +659,7 @@ static int i_APCI3120_Reset(struct comedi_device *dev)
return 0;
}
-static int i_APCI3120_ExttrigEnable(struct comedi_device *dev)
+static int apci3120_exttrig_enable(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
@@ -672,7 +668,7 @@ static int i_APCI3120_ExttrigEnable(struct comedi_device *dev)
return 0;
}
-static int i_APCI3120_ExttrigDisable(struct comedi_device *dev)
+static int apci3120_exttrig_disable(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
@@ -681,8 +677,8 @@ static int i_APCI3120_ExttrigDisable(struct comedi_device *dev)
return 0;
}
-static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int apci3120_cancel(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct addi_private *devpriv = dev->private;
@@ -705,7 +701,7 @@ static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,
* devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */
/* Disable ext trigger */
- i_APCI3120_ExttrigDisable(dev);
+ apci3120_exttrig_disable(dev);
devpriv->us_OutputRegister = 0;
/* stop counters */
@@ -723,21 +719,19 @@ static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,
inw(dev->iobase + APCI3120_RD_STATUS);
devpriv->ui_AiActualScan = 0;
s->async->cur_chan = 0;
- devpriv->b_AiContinuous = 0;
devpriv->ui_DmaActualBuffer = 0;
- devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+ devpriv->ai_running = 0;
devpriv->b_InterruptMode = APCI3120_EOC_MODE;
devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
- i_APCI3120_Reset(dev);
+ apci3120_reset(dev);
return 0;
}
-static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
+static int apci3120_ai_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
{
- const struct addi_board *this_board = comedi_board(dev);
int err = 0;
/* Step 1 : check if triggers are trivially valid */
@@ -770,20 +764,16 @@ static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev,
if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */
err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000);
- if (cmd->convert_src == TRIG_TIMER) { /* Test Acquisition timing */
- if (cmd->scan_begin_src == TRIG_TIMER) {
- if (cmd->convert_arg)
- err |= cfc_check_trigger_arg_min(
- &cmd->convert_arg, 10000);
- } else {
+ if (cmd->scan_begin_src == TRIG_TIMER) {
+ if (cmd->convert_arg)
err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
- 10000);
- }
+ 10000);
+ } else {
+ err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
}
err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
- err |= cfc_check_trigger_arg_max(&cmd->chanlist_len,
- this_board->i_AiChannelList);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
if (cmd->stop_src == TRIG_COUNT)
err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
@@ -795,15 +785,10 @@ static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev,
/* step 4: fix up any arguments */
- if (cmd->convert_src == TRIG_TIMER) {
-
- if (cmd->scan_begin_src == TRIG_TIMER &&
- cmd->scan_begin_arg <
- cmd->convert_arg * cmd->scan_end_arg) {
- cmd->scan_begin_arg =
- cmd->convert_arg * cmd->scan_end_arg;
- err++;
- }
+ if (cmd->scan_begin_src == TRIG_TIMER &&
+ cmd->scan_begin_arg < cmd->convert_arg * cmd->scan_end_arg) {
+ cmd->scan_begin_arg = cmd->convert_arg * cmd->scan_end_arg;
+ err |= -EINVAL;
}
if (err)
@@ -818,22 +803,19 @@ static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev,
* If DMA is configured does DMA initialization otherwise does the
* acquisition with EOS interrupt.
*/
-static int i_APCI3120_CyclicAnalogInput(int mode,
- struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int apci3120_cyclic_ai(int mode,
+ struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
const struct addi_board *this_board = comedi_board(dev);
struct addi_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned char b_Tmp;
unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
0, dmalen1 = 0, ui_TimerValue2 =
0, ui_TimerValue0, ui_ConvertTiming;
unsigned short us_TmpValue;
- /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
- /* devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; */
- /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
-
/*******************/
/* Resets the FIFO */
/*******************/
@@ -843,12 +825,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode,
/* inw(dev->iobase+APCI3120_RD_STATUS); */
/* END JK 07.05.04: Comparison between WIN32 and Linux driver */
- /***************************/
- /* Acquisition initialized */
- /***************************/
- /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
- devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE;
- /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
+ devpriv->ai_running = 1;
/* clear software registers */
devpriv->b_TimerSelectMode = 0;
@@ -895,17 +872,17 @@ static int i_APCI3120_CyclicAnalogInput(int mode,
devpriv->ui_DmaActualBuffer = 0;
/* value for timer2 minus -2 has to be done .....dunno y?? */
- ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2;
- ui_ConvertTiming = devpriv->ui_AiTimer0;
+ ui_TimerValue2 = cmd->stop_arg - 2;
+ ui_ConvertTiming = cmd->convert_arg;
if (mode == 2)
- ui_DelayTiming = devpriv->ui_AiTimer1;
+ ui_DelayTiming = cmd->scan_begin_arg;
/**********************************/
/* Initializes the sequence array */
/**********************************/
- if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels,
- devpriv->pui_AiChannelList, 0))
+ if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels,
+ cmd->chanlist, 0))
return -EINVAL;
us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS);
@@ -957,7 +934,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode,
/*** EL241003 End ******************************************************************************/
if (devpriv->b_ExttrigEnable == APCI3120_ENABLE)
- i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */
+ apci3120_exttrig_enable(dev); /* activate EXT trigger */
switch (mode) {
case 1:
/* init timer0 in mode 2 */
@@ -1042,7 +1019,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode,
outb(devpriv->b_ModeSelectRegister,
dev->iobase + APCI3120_WRITE_MODE_SELECT);
- if (!devpriv->b_AiContinuous) {
+ if (cmd->stop_src == TRIG_COUNT) {
/*
* configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
* disable it (Set Bit D14 to 0)
@@ -1110,6 +1087,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode,
}
} else {
/* If DMA Enabled */
+ unsigned int scan_bytes = cmd->scan_end_arg * sizeof(short);
/* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
/* inw(dev->iobase+0); reset EOC bit */
@@ -1128,37 +1106,38 @@ static int i_APCI3120_CyclicAnalogInput(int mode,
dmalen0 = devpriv->ui_DmaBufferSize[0];
dmalen1 = devpriv->ui_DmaBufferSize[1];
- if (!devpriv->b_AiContinuous) {
-
- if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { /* must we fill full first buffer? */
- dmalen0 =
- devpriv->ui_AiNbrofScans *
- devpriv->ui_AiScanLength * 2;
- } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) /* and must we fill full second buffer when first is once filled? */
- dmalen1 =
- devpriv->ui_AiNbrofScans *
- devpriv->ui_AiScanLength * 2 - dmalen0;
+ if (cmd->stop_src == TRIG_COUNT) {
+ /*
+ * Must we fill full first buffer? And must we fill
+ * full second buffer when first is once filled?
+ */
+ if (dmalen0 > (cmd->stop_arg * scan_bytes)) {
+ dmalen0 = cmd->stop_arg * scan_bytes;
+ } else if (dmalen1 > (cmd->stop_arg * scan_bytes -
+ dmalen0))
+ dmalen1 = cmd->stop_arg * scan_bytes -
+ dmalen0;
}
- if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) {
+ if (cmd->flags & TRIG_WAKE_EOS) {
/* don't we want wake up every scan? */
- if (dmalen0 > (devpriv->ui_AiScanLength * 2)) {
- dmalen0 = devpriv->ui_AiScanLength * 2;
- if (devpriv->ui_AiScanLength & 1)
+ if (dmalen0 > scan_bytes) {
+ dmalen0 = scan_bytes;
+ if (cmd->scan_end_arg & 1)
dmalen0 += 2;
}
- if (dmalen1 > (devpriv->ui_AiScanLength * 2)) {
- dmalen1 = devpriv->ui_AiScanLength * 2;
- if (devpriv->ui_AiScanLength & 1)
+ if (dmalen1 > scan_bytes) {
+ dmalen1 = scan_bytes;
+ if (cmd->scan_end_arg & 1)
dmalen1 -= 2;
if (dmalen1 < 4)
dmalen1 = 4;
}
} else { /* isn't output buff smaller that our DMA buff? */
- if (dmalen0 > (devpriv->ui_AiDataLength))
- dmalen0 = devpriv->ui_AiDataLength;
- if (dmalen1 > (devpriv->ui_AiDataLength))
- dmalen1 = devpriv->ui_AiDataLength;
+ if (dmalen0 > s->async->prealloc_bufsz)
+ dmalen0 = s->async->prealloc_bufsz;
+ if (dmalen1 > s->async->prealloc_bufsz)
+ dmalen1 = s->async->prealloc_bufsz;
}
devpriv->ui_DmaBufferUsesize[0] = dmalen0;
devpriv->ui_DmaBufferUsesize[1] = dmalen1;
@@ -1296,8 +1275,8 @@ static int i_APCI3120_CyclicAnalogInput(int mode,
/* END JK 07.05.04: Comparison between WIN32 and Linux driver */
}
- if ((devpriv->us_UseDma == APCI3120_DISABLE)
- && !devpriv->b_AiContinuous) {
+ if (devpriv->us_UseDma == APCI3120_DISABLE &&
+ cmd->stop_src == TRIG_COUNT) {
/* set gate 2 to start conversion */
devpriv->us_OutputRegister =
devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
@@ -1333,57 +1312,24 @@ static int i_APCI3120_CyclicAnalogInput(int mode,
* Does asynchronous acquisition.
* Determines the mode 1 or 2.
*/
-static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int apci3120_ai_cmd(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct addi_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
/* loading private structure with cmd structure inputs */
- devpriv->ui_AiFlags = cmd->flags;
devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
- devpriv->ui_AiScanLength = cmd->scan_end_arg;
- devpriv->pui_AiChannelList = cmd->chanlist;
-
- /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */
- devpriv->ui_AiDataLength = s->async->prealloc_bufsz;
-
- if (cmd->stop_src == TRIG_COUNT)
- devpriv->ui_AiNbrofScans = cmd->stop_arg;
- else
- devpriv->ui_AiNbrofScans = 0;
-
- devpriv->ui_AiTimer0 = 0; /* variables changed to timer0,timer1 */
- devpriv->ui_AiTimer1 = 0;
- if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1))
- devpriv->b_AiContinuous = 1; /* user want neverending analog acquisition */
- /* stopped using cancel */
if (cmd->start_src == TRIG_EXT)
devpriv->b_ExttrigEnable = APCI3120_ENABLE;
else
devpriv->b_ExttrigEnable = APCI3120_DISABLE;
- if (cmd->scan_begin_src == TRIG_FOLLOW) {
- /* mode 1 or 3 */
- if (cmd->convert_src == TRIG_TIMER) {
- /* mode 1 */
-
- devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */
- /* return this_board->ai_cmd(1,dev,s); */
- return i_APCI3120_CyclicAnalogInput(1, dev, s);
- }
-
- }
- if ((cmd->scan_begin_src == TRIG_TIMER)
- && (cmd->convert_src == TRIG_TIMER)) {
- /* mode 2 */
- devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
- devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */
- /* return this_board->ai_cmd(2,dev,s); */
- return i_APCI3120_CyclicAnalogInput(2, dev, s);
- }
- return -1;
+ if (cmd->scan_begin_src == TRIG_FOLLOW)
+ return apci3120_cyclic_ai(1, dev, s);
+ else /* TRIG_TIMER */
+ return apci3120_cyclic_ai(2, dev, s);
}
/*
@@ -1395,11 +1341,12 @@ static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,
unsigned int num_samples)
{
struct addi_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
devpriv->ui_AiActualScan +=
- (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength;
+ (s->async->cur_chan + num_samples) / cmd->scan_end_arg;
s->async->cur_chan += num_samples;
- s->async->cur_chan %= devpriv->ui_AiScanLength;
+ s->async->cur_chan %= cmd->scan_end_arg;
cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
}
@@ -1410,11 +1357,12 @@ static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,
* For continuous DMA it reinitializes the DMA operation.
* For single mode DMA it stop the acquisition.
*/
-static void v_APCI3120_InterruptDma(int irq, void *d)
+static void apci3120_interrupt_dma(int irq, void *d)
{
struct comedi_device *dev = d;
struct addi_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned int next_dma_buf, samplesinbuf;
unsigned long low_word, high_word, var;
unsigned int ui_Tmp;
@@ -1429,9 +1377,7 @@ static void v_APCI3120_InterruptDma(int irq, void *d)
}
if (samplesinbuf & 1) {
comedi_error(dev, "Odd count of bytes in DMA ring!");
- i_APCI3120_StopCyclicAcquisition(dev, s);
- devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
-
+ apci3120_cancel(dev, s);
return;
}
samplesinbuf = samplesinbuf >> 1; /* number of received samples */
@@ -1492,16 +1438,15 @@ static void v_APCI3120_InterruptDma(int irq, void *d)
devpriv->ul_DmaBufferVirtual[devpriv->
ui_DmaActualBuffer], samplesinbuf);
- if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) {
+ if (!(cmd->flags & TRIG_WAKE_EOS)) {
s->async->events |= COMEDI_CB_EOS;
comedi_event(dev, s);
}
}
- if (!devpriv->b_AiContinuous)
- if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
+ if (cmd->stop_src == TRIG_COUNT)
+ if (devpriv->ui_AiActualScan >= cmd->stop_arg) {
/* all data sampled */
- i_APCI3120_StopCyclicAcquisition(dev, s);
- devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+ apci3120_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
comedi_event(dev, s);
return;
@@ -1565,19 +1510,17 @@ static void v_APCI3120_InterruptDma(int irq, void *d)
* This function handles EOS interrupt.
* This function copies the acquired data(from FIFO) to Comedi buffer.
*/
-static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
+static int apci3120_interrupt_handle_eos(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
int n_chan, i;
- struct comedi_subdevice *s = &dev->subdevices[0];
int err = 1;
n_chan = devpriv->ui_AiNbrofChannels;
- s->async->events = 0;
-
for (i = 0; i < n_chan; i++)
- err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
+ err &= comedi_buf_put(s, inw(dev->iobase + 0));
s->async->events |= COMEDI_CB_EOS;
@@ -1589,15 +1532,15 @@ static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
return 0;
}
-static void v_APCI3120_Interrupt(int irq, void *d)
+static void apci3120_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct addi_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
unsigned short int_daq;
unsigned int int_amcc, ui_Check, i;
unsigned short us_TmpValue;
unsigned char b_DummyRead;
- struct comedi_subdevice *s = &dev->subdevices[0];
ui_Check = 1;
@@ -1615,7 +1558,7 @@ static void v_APCI3120_Interrupt(int irq, void *d)
if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
/* Disable ext trigger */
- i_APCI3120_ExttrigDisable(dev);
+ apci3120_exttrig_disable(dev);
devpriv->b_ExttrigEnable = APCI3120_DISABLE;
}
/* clear the timer 2 interrupt */
@@ -1653,9 +1596,9 @@ static void v_APCI3120_Interrupt(int irq, void *d)
if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* enable this in without DMA ??? */
- if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
+ if (devpriv->ai_running) {
ui_Check = 0;
- i_APCI3120_InterruptHandleEos(dev);
+ apci3120_interrupt_handle_eos(dev);
devpriv->ui_AiActualScan++;
devpriv->b_ModeSelectRegister =
devpriv->
@@ -1695,8 +1638,6 @@ static void v_APCI3120_Interrupt(int irq, void *d)
switch (devpriv->b_Timer2Mode) {
case APCI3120_COUNTER:
-
- devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
devpriv->b_ModeSelectRegister =
devpriv->
b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
@@ -1711,8 +1652,7 @@ static void v_APCI3120_Interrupt(int irq, void *d)
dev->iobase + APCI3120_WR_ADDRESS);
/* stop timer 0 and timer 1 */
- i_APCI3120_StopCyclicAcquisition(dev, s);
- devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+ apci3120_cancel(dev, s);
/* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */
s->async->events |= COMEDI_CB_EOA;
@@ -1751,7 +1691,7 @@ static void v_APCI3120_Interrupt(int irq, void *d)
}
if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
- if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
+ if (devpriv->ai_running) {
/****************************/
/* Clear Timer Write TC int */
@@ -1765,7 +1705,8 @@ static void v_APCI3120_Interrupt(int irq, void *d)
/* Clears the timer status register */
/************************************/
inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
- v_APCI3120_InterruptDma(irq, d); /* do some data transfer */
+ /* do some data transfer */
+ apci3120_interrupt_dma(irq, d);
} else {
/* Stops the Timer */
outw(devpriv->
@@ -1787,7 +1728,7 @@ static void v_APCI3120_Interrupt(int irq, void *d)
* data[1] = Timer constant
* data[2] = Timer2 interrupt (1)enable or(0) disable
*/
-static int i_APCI3120_InsnConfigTimer(struct comedi_device *dev,
+static int apci3120_config_insn_timer(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
@@ -1932,7 +1873,7 @@ static int i_APCI3120_InsnConfigTimer(struct comedi_device *dev,
* = 1 Timer
* = 2 Watch dog
*/
-static int i_APCI3120_InsnWriteTimer(struct comedi_device *dev,
+static int apci3120_write_insn_timer(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
@@ -2104,7 +2045,7 @@ static int i_APCI3120_InsnWriteTimer(struct comedi_device *dev,
* for watchdog: data[0] = 0 (still running)
* = 1 (run down)
*/
-static int i_APCI3120_InsnReadTimer(struct comedi_device *dev,
+static int apci3120_read_insn_timer(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
@@ -2189,10 +2130,10 @@ static int apci3120_do_insn_bits(struct comedi_device *dev,
return insn->n;
}
-static int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3120_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ui_Range, ui_Channel;
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
index dc73d4d348e..f540394d17b 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
@@ -1268,7 +1268,7 @@ static int i_APCI3200_ReadCJCCalGain(struct comedi_device *dev,
return 0;
}
-static int i_APCI3200_Reset(struct comedi_device *dev)
+static int apci3200_reset(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
int i_Temp;
@@ -1322,10 +1322,10 @@ static int i_APCI3200_Reset(struct comedi_device *dev)
* data[7] : Channel current source from eeprom
* data[8] : Channle gain factor from eeprom
*/
-static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3200_ai_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
unsigned int ui_DummyValue = 0;
int i_ConvertCJCCalibration;
@@ -1336,7 +1336,7 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev,
if (s_BoardInfos[dev->minor].i_Initialised == 0)
/* END JK 06.07.04: Management of sevrals boards */
{
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return -EINVAL;
} /* if(i_Initialised==0); */
@@ -1586,7 +1586,7 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev,
break;
default:
printk("\nThe parameters passed are in error\n");
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return -EINVAL;
} /* switch(insn->unused[0]) */
@@ -1626,10 +1626,10 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev,
* = 2 RTD 3 wire connection
* = 3 RTD 4 wire connection
*/
-static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3200_ai_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ul_Config = 0, ul_Temp = 0;
@@ -1970,7 +1970,7 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev,
} /* switch(data[11]) */
} /* elseif(data[12]==0 || data[12]==1) */
if (i_err) {
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return -EINVAL;
}
/* if(i_ScanType!=1) */
@@ -2079,7 +2079,7 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev,
/* END JK 06.07.04: Management of sevrals boards */
insn->unused[0] = 0;
- i_APCI3200_ReadAnalogInput(dev, s, insn, &ui_Dummy);
+ apci3200_ai_read(dev, s, insn, &ui_Dummy);
}
return insn->n;
@@ -2095,10 +2095,10 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev,
* data[1] : calibration offset
* data[2] : calibration gain
*/
-static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3200_ai_bits_test(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct addi_private *devpriv = dev->private;
unsigned int ui_Configuration = 0;
@@ -2107,12 +2107,12 @@ static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev,
/* if(i_Initialised==0) */
if (s_BoardInfos[dev->minor].i_Initialised == 0) {
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return -EINVAL;
} /* if(i_Initialised==0); */
if (data[0] != 0 && data[0] != 1) {
printk("\nError in selection of functionality\n");
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return -EINVAL;
} /* if(data[0]!=0 && data[0]!=1) */
@@ -2202,18 +2202,18 @@ static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev,
return insn->n;
}
-static int i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3200_ai_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return insn->n;
}
-static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
+static int apci3200_ai_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
{
int err = 0;
@@ -2221,12 +2221,11 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev,
unsigned int ui_ConvertTimeBase = 0;
unsigned int ui_DelayTime = 0;
unsigned int ui_DelayTimeBase = 0;
- int i_Triggermode = 0;
- int i_TriggerEdge = 0;
int i_NbrOfChannel = 0;
int i_Cpt = 0;
double d_ConversionTimeForAllChannels = 0.0;
double d_SCANTimeNewUnit = 0.0;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -2241,7 +2240,7 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev,
err |= -EINVAL;
if (err) {
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return 1;
}
@@ -2253,23 +2252,37 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev,
/* Step 2b : and mutually compatible */
- if (cmd->start_src == TRIG_EXT) {
- i_TriggerEdge = cmd->start_arg & 0xFFFF;
- i_Triggermode = cmd->start_arg >> 16;
- if (i_TriggerEdge < 1 || i_TriggerEdge > 3) {
- err++;
- printk("\nThe trigger edge selection is in error\n");
+ if (err) {
+ apci3200_reset(dev);
+ return 2;
+ }
+
+ /* Step 3: check if arguments are trivially valid */
+
+ switch (cmd->start_src) {
+ case TRIG_NOW:
+ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ break;
+ case TRIG_EXT:
+ /* validate the trigger edge selection */
+ arg = cmd->start_arg & 0xffff;
+ if (arg < 1 || arg > 3) {
+ cmd->start_arg &= ~0xffff;
+ cmd->start_arg |= 1;
+ err |= -EINVAL;
}
- if (i_Triggermode != 2) {
- err++;
- printk("\nThe trigger mode selection is in error\n");
+ /* validate the trigger mode selection */
+ arg = cmd->start_arg >> 16;
+ if (arg != 2) {
+ cmd->start_arg &= ~(0xffff << 16);
+ cmd->start_arg |= (2 << 16);
+ err |= -EINVAL;
}
+ break;
}
- if (err) {
- i_APCI3200_Reset(dev);
- return 2;
- }
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+
/* i_FirstChannel=cmd->chanlist[0]; */
s_BoardInfos[dev->minor].i_FirstChannel = cmd->chanlist[0];
/* i_LastChannel=cmd->chanlist[1]; */
@@ -2308,7 +2321,7 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev,
printk("\nThe Delay time value is in error\n");
}
if (err) {
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return 3;
}
fpu_begin();
@@ -2366,15 +2379,15 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev,
} /* else if(cmd->scan_begin_src==TRIG_FOLLOW) */
if (err) {
- i_APCI3200_Reset(dev);
+ apci3200_reset(dev);
return 4;
}
return 0;
}
-static int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int apci3200_cancel(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct addi_private *devpriv = dev->private;
unsigned int ui_Configuration = 0;
@@ -2410,8 +2423,8 @@ static int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev,
* Does asynchronous acquisition
* Determines the mode 1 or 2.
*/
-static int i_APCI3200_CommandAnalogInput(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int apci3200_ai_cmd(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct addi_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
@@ -2590,8 +2603,8 @@ static int i_APCI3200_CommandAnalogInput(struct comedi_device *dev,
static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
unsigned int ui_StatusRegister = 0;
- struct comedi_subdevice *s = &dev->subdevices[0];
/* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */
/* comedi_async *async = s->async; */
@@ -2619,7 +2632,6 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev)
/* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */
/* This value is not used */
/* ui_ChannelNumber = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 24); */
- s->async->events = 0;
/* END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */
/*************************************/
@@ -2690,8 +2702,7 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev)
s->async->events |= COMEDI_CB_EOS;
/* Test if enougth memory is available and allocate it for 7 values */
- /* n = comedi_buf_write_alloc(s->async, 7*sizeof(unsigned int)); */
- n = comedi_buf_write_alloc(s->async,
+ n = comedi_buf_write_alloc(s,
(7 + 12) * sizeof(unsigned int));
/* If not enough memory available, event is set to Comedi Buffer Error */
@@ -2700,12 +2711,12 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev)
s->async->events |= COMEDI_CB_ERROR;
}
/* Write all 7 scan values in the comedi buffer */
- comedi_buf_memcpy_to(s->async, 0,
+ comedi_buf_memcpy_to(s, 0,
(unsigned int *) s_BoardInfos[dev->minor].
ui_ScanValueArray, (7 + 12) * sizeof(unsigned int));
/* Update comedi buffer pinters indexes */
- comedi_buf_write_free(s->async,
+ comedi_buf_write_free(s,
(7 + 12) * sizeof(unsigned int));
/* Send events */
@@ -2730,7 +2741,7 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev)
return 0;
}
-static void v_APCI3200_Interrupt(int irq, void *d)
+static void apci3200_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct addi_private *devpriv = dev->private;
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
index ebc1534a8df..e82c3fcd048 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
@@ -16,10 +16,10 @@
* data[2] : Time Unit
* data[3] : Reload Value
*/
-static int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3501_config_insn_timer(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct apci3501_private *devpriv = dev->private;
unsigned int ul_Command1 = 0;
@@ -86,10 +86,10 @@ static int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev,
* 0 Stop
* 2 Trigger
*/
-static int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3501_write_insn_timer(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct apci3501_private *devpriv = dev->private;
unsigned int ul_Command1 = 0;
@@ -102,11 +102,7 @@ static int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *d
ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL;
/* Enable the Watchdog */
outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG);
- }
-
- else if (data[1] == 0) /* Stop The Watchdog */
- {
- /* Stop The Watchdog */
+ } else if (data[1] == 0) { /* Stop The Watchdog */
ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG);
ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
outl(0x0, dev->iobase + APCI3501_TIMER_CTRL_REG);
@@ -153,10 +149,10 @@ static int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *d
* 2 Watchdog
* data[1] : Timer Counter Watchdog Number
*/
-static int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int apci3501_read_insn_timer(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct apci3501_private *devpriv = dev->private;
diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c
index 8d229b2f097..4da9db35b8e 100644
--- a/drivers/staging/comedi/drivers/addi_apci_035.c
+++ b/drivers/staging/comedi/drivers/addi_apci_035.c
@@ -27,13 +27,13 @@ static const struct addi_board apci035_boardtypes[] = {
.i_Timer = 1,
.ui_MinAcquisitiontimeNs = 10000,
.ui_MinDelaytimeNs = 100000,
- .interrupt = v_APCI035_Interrupt,
- .reset = i_APCI035_Reset,
- .ai_config = i_APCI035_ConfigAnalogInput,
- .ai_read = i_APCI035_ReadAnalogInput,
- .timer_config = i_APCI035_ConfigTimerWatchdog,
- .timer_write = i_APCI035_StartStopWriteTimerWatchdog,
- .timer_read = i_APCI035_ReadTimerWatchdog,
+ .interrupt = apci035_interrupt,
+ .reset = apci035_reset,
+ .ai_config = apci035_ai_config,
+ .ai_read = apci035_ai_read,
+ .timer_config = apci035_timer_config,
+ .timer_write = apci035_timer_write,
+ .timer_read = apci035_timer_read,
},
};
@@ -58,7 +58,7 @@ static int apci035_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &apci035_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(apci035_pci_table) = {
+static const struct pci_device_id apci035_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x0300) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c
index 34ab0679e99..1b2e7c040c9 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1032.c
@@ -198,7 +198,7 @@ static int apci1032_cos_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
- err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
if (err)
@@ -262,7 +262,7 @@ static irqreturn_t apci1032_interrupt(int irq, void *d)
outl(ctrl & ~APCI1032_CTRL_INT_ENA, dev->iobase + APCI1032_CTRL_REG);
s->state = inl(dev->iobase + APCI1032_STATUS_REG) & 0xffff;
- comedi_buf_put(s->async, s->state);
+ comedi_buf_put(s, s->state);
s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
comedi_event(dev, s);
@@ -325,13 +325,14 @@ static int apci1032_auto_attach(struct comedi_device *dev,
s = &dev->subdevices[1];
if (dev->irq) {
dev->read_subdev = s;
- s->type = COMEDI_SUBD_DI | SDF_CMD_READ;
- s->subdev_flags = SDF_READABLE;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
s->n_chan = 1;
s->maxdata = 1;
s->range_table = &range_digital;
s->insn_config = apci1032_cos_insn_config;
s->insn_bits = apci1032_cos_insn_bits;
+ s->len_chanlist = 1;
s->do_cmdtest = apci1032_cos_cmdtest;
s->do_cmd = apci1032_cos_cmd;
s->cancel = apci1032_cos_cancel;
@@ -364,7 +365,7 @@ static int apci1032_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &apci1032_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(apci1032_pci_table) = {
+static const struct pci_device_id apci1032_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1003) },
{ 0 }
};
@@ -379,5 +380,5 @@ static struct pci_driver apci1032_pci_driver = {
module_comedi_pci_driver(apci1032_driver, apci1032_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("ADDI-DATA APCI-1032, 32 channel DI boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c
index ae9ded63dce..eab75eb2647 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1500.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1500.c
@@ -20,19 +20,19 @@ static const struct addi_board apci1500_boardtypes[] = {
.i_NbrDoChannel = 16,
.i_DoMaxdata = 0xffff,
.i_Timer = 1,
- .interrupt = v_APCI1500_Interrupt,
- .reset = i_APCI1500_Reset,
- .di_config = i_APCI1500_ConfigDigitalInputEvent,
- .di_read = i_APCI1500_Initialisation,
- .di_write = i_APCI1500_StartStopInputEvent,
+ .interrupt = apci1500_interrupt,
+ .reset = apci1500_reset,
+ .di_config = apci1500_di_config,
+ .di_read = apci1500_di_read,
+ .di_write = apci1500_di_write,
.di_bits = apci1500_di_insn_bits,
- .do_config = i_APCI1500_ConfigDigitalOutputErrorInterrupt,
- .do_write = i_APCI1500_WriteDigitalOutput,
- .do_bits = i_APCI1500_ConfigureInterrupt,
- .timer_config = i_APCI1500_ConfigCounterTimerWatchdog,
- .timer_write = i_APCI1500_StartStopTriggerTimerCounterWatchdog,
- .timer_read = i_APCI1500_ReadInterruptMask,
- .timer_bits = i_APCI1500_ReadCounterTimerWatchdog,
+ .do_config = apci1500_do_config,
+ .do_write = apci1500_do_write,
+ .do_bits = apci1500_do_bits,
+ .timer_config = apci1500_timer_config,
+ .timer_write = apci1500_timer_write,
+ .timer_read = apci1500_timer_read,
+ .timer_bits = apci1500_timer_bits,
},
};
@@ -57,7 +57,7 @@ static int apci1500_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &apci1500_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(apci1500_pci_table) = {
+static const struct pci_device_id apci1500_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80fc) },
{ 0 }
};
@@ -72,5 +72,5 @@ static struct pci_driver apci1500_pci_driver = {
module_comedi_pci_driver(apci1500_driver, apci1500_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("ADDI-DATA APCI-1500, 16 channel DI / 16 channel DO boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c
index 9d1b1425c60..e9c5291c77c 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1516.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1516.c
@@ -206,7 +206,7 @@ static int apci1516_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &apci1516_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(apci1516_pci_table) = {
+static const struct pci_device_id apci1516_pci_table[] = {
{ PCI_VDEVICE(ADDIDATA, 0x1000), BOARD_APCI1016 },
{ PCI_VDEVICE(ADDIDATA, 0x1001), BOARD_APCI1516 },
{ PCI_VDEVICE(ADDIDATA, 0x1002), BOARD_APCI2016 },
diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c
index c5717d63e16..13d9962b47e 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1564.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1564.c
@@ -3,50 +3,168 @@
#include "../comedidev.h"
#include "comedi_fc.h"
-#include "amcc_s5933.h"
#include "addi-data/addi_common.h"
-#include "addi-data/addi_eeprom.c"
#include "addi-data/hwdrv_apci1564.c"
-#include "addi-data/addi_common.c"
-
-static const struct addi_board apci1564_boardtypes[] = {
- {
- .pc_DriverName = "apci1564",
- .i_IorangeBase1 = APCI1564_ADDRESS_RANGE,
- .i_PCIEeprom = ADDIDATA_EEPROM,
- .pc_EepromChip = ADDIDATA_93C76,
- .i_NbrDiChannel = 32,
- .i_NbrDoChannel = 32,
- .i_DoMaxdata = 0xffffffff,
- .i_Timer = 1,
- .interrupt = v_APCI1564_Interrupt,
- .reset = i_APCI1564_Reset,
- .di_config = i_APCI1564_ConfigDigitalInput,
- .di_bits = apci1564_di_insn_bits,
- .do_config = i_APCI1564_ConfigDigitalOutput,
- .do_bits = apci1564_do_insn_bits,
- .do_read = i_APCI1564_ReadInterruptStatus,
- .timer_config = i_APCI1564_ConfigTimerCounterWatchdog,
- .timer_write = i_APCI1564_StartStopWriteTimerCounterWatchdog,
- .timer_read = i_APCI1564_ReadTimerCounterWatchdog,
- },
-};
+
+static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
+{
+ apci1564_interrupt(irq, d);
+ return IRQ_RETVAL(1);
+}
+
+static int apci1564_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct addi_private *devpriv = dev->private;
+
+ data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_DI_REG);
+
+ return insn->n;
+}
+
+static int apci1564_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct addi_private *devpriv = dev->private;
+
+ s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DO_REG);
+
+ if (comedi_dio_update_state(s, data))
+ outl(s->state, devpriv->i_IobaseAmcc + APCI1564_DO_REG);
+
+ data[1] = s->state;
+
+ return insn->n;
+}
+
+static int apci1564_reset(struct comedi_device *dev)
+{
+ struct addi_private *devpriv = dev->private;
+
+ ui_Type = 0;
+
+ /* Disable the input interrupts and reset status register */
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG);
+ inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG);
+
+ /* Reset the output channels and disable interrupts */
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG);
+
+ /* Reset the watchdog registers */
+ addi_watchdog_reset(devpriv->i_IobaseAmcc + APCI1564_WDOG_REG);
+
+ /* Reset the timer registers */
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG);
+ outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_RELOAD_REG);
+
+ /* Reset the counter registers */
+ outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1));
+ outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2));
+ outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3));
+ outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4));
+
+ return 0;
+}
static int apci1564_auto_attach(struct comedi_device *dev,
- unsigned long context)
+ unsigned long context_unused)
+{
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct addi_private *devpriv;
+ struct comedi_subdevice *s;
+ int ret;
+
+ dev->board_name = dev->driver->driver_name;
+
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+ if (!devpriv)
+ return -ENOMEM;
+
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
+
+ dev->iobase = pci_resource_start(pcidev, 1);
+ devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0);
+
+ apci1564_reset(dev);
+
+ if (pcidev->irq > 0) {
+ ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = pcidev->irq;
+ }
+
+ ret = comedi_alloc_subdevices(dev, 3);
+ if (ret)
+ return ret;
+
+ /* Allocate and Initialise DI Subdevice Structures */
+ s = &dev->subdevices[0];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 32;
+ s->maxdata = 1;
+ s->len_chanlist = 32;
+ s->range_table = &range_digital;
+ s->insn_config = apci1564_di_config;
+ s->insn_bits = apci1564_di_insn_bits;
+
+ /* Allocate and Initialise DO Subdevice Structures */
+ s = &dev->subdevices[1];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 32;
+ s->maxdata = 0xffffffff;
+ s->len_chanlist = 32;
+ s->range_table = &range_digital;
+ s->insn_config = apci1564_do_config;
+ s->insn_bits = apci1564_do_insn_bits;
+ s->insn_read = apci1564_do_read;
+
+ /* Allocate and Initialise Timer Subdevice Structures */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_TIMER;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 1;
+ s->maxdata = 0;
+ s->len_chanlist = 1;
+ s->range_table = &range_digital;
+ s->insn_write = apci1564_timer_write;
+ s->insn_read = apci1564_timer_read;
+ s->insn_config = apci1564_timer_config;
+
+ return 0;
+}
+
+static void apci1564_detach(struct comedi_device *dev)
{
- dev->board_ptr = &apci1564_boardtypes[0];
+ struct addi_private *devpriv = dev->private;
- return addi_auto_attach(dev, context);
+ if (devpriv) {
+ if (dev->iobase)
+ apci1564_reset(dev);
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ }
+ comedi_pci_disable(dev);
}
static struct comedi_driver apci1564_driver = {
.driver_name = "addi_apci_1564",
.module = THIS_MODULE,
.auto_attach = apci1564_auto_attach,
- .detach = i_ADDI_Detach,
+ .detach = apci1564_detach,
};
static int apci1564_pci_probe(struct pci_dev *dev,
@@ -55,7 +173,7 @@ static int apci1564_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &apci1564_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(apci1564_pci_table) = {
+static const struct pci_device_id apci1564_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1006) },
{ 0 }
};
@@ -70,5 +188,5 @@ static struct pci_driver apci1564_pci_driver = {
module_comedi_pci_driver(apci1564_driver, apci1564_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("ADDI-DATA APCI-1564, 32 channel DI / 32 channel DO boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c
index 5ee204bcbee..28df4b50b87 100644
--- a/drivers/staging/comedi/drivers/addi_apci_16xx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c
@@ -168,7 +168,7 @@ static int apci16xx_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &apci16xx_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(apci16xx_pci_table) = {
+static const struct pci_device_id apci16xx_pci_table[] = {
{ PCI_VDEVICE(ADDIDATA, 0x1009), BOARD_APCI1648 },
{ PCI_VDEVICE(ADDIDATA, 0x100a), BOARD_APCI1696 },
{ 0 }
diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c
index c77ee8732d3..be0a8a7bd3b 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2032.c
@@ -197,6 +197,7 @@ static irqreturn_t apci2032_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_cmd *cmd = &s->async->cmd;
struct apci2032_int_private *subpriv;
unsigned int val;
bool do_event = false;
@@ -222,21 +223,20 @@ static irqreturn_t apci2032_interrupt(int irq, void *d)
*/
if (subpriv->active && (val & subpriv->enabled_isns) != 0) {
- unsigned short bits;
- unsigned int n, len;
- unsigned int *chanlist;
+ unsigned short bits = 0;
+ int i;
/* Bits in scan data correspond to indices in channel list. */
- bits = 0;
- len = s->async->cmd.chanlist_len;
- chanlist = &s->async->cmd.chanlist[0];
- for (n = 0; n < len; n++)
- if ((val & (1U << CR_CHAN(chanlist[n]))) != 0)
- bits |= 1U << n;
-
- if (comedi_buf_put(s->async, bits)) {
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+
+ if (val & (1 << chan))
+ bits |= (1 << i);
+ }
+
+ if (comedi_buf_put(s, bits)) {
s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
- if (s->async->cmd.stop_src == TRIG_COUNT &&
+ if (cmd->stop_src == TRIG_COUNT &&
subpriv->stop_count > 0) {
subpriv->stop_count--;
if (subpriv->stop_count == 0) {
@@ -359,7 +359,7 @@ static int apci2032_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &apci2032_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(apci2032_pci_table) = {
+static const struct pci_device_id apci2032_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1004) },
{ 0 }
};
@@ -374,5 +374,5 @@ static struct pci_driver apci2032_pci_driver = {
module_comedi_pci_driver(apci2032_driver, apci2032_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("ADDI-DATA APCI-2032, 32 channel DO boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c
index 7fb32e778d8..e1a916546d1 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2200.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2200.c
@@ -134,7 +134,7 @@ static int apci2200_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &apci2200_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(apci2200_pci_table) = {
+static const struct pci_device_id apci2200_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1005) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c
index 67d09e8afb2..0cfb12fa1cb 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3120.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3120.c
@@ -26,7 +26,7 @@ static const struct addi_board apci3120_boardtypes[] = {
.i_NbrDiChannel = 4,
.i_NbrDoChannel = 4,
.i_DoMaxdata = 0x0f,
- .interrupt = v_APCI3120_Interrupt,
+ .interrupt = apci3120_interrupt,
},
[BOARD_APCI3001] = {
.pc_DriverName = "apci3001",
@@ -37,7 +37,7 @@ static const struct addi_board apci3120_boardtypes[] = {
.i_NbrDiChannel = 4,
.i_NbrDoChannel = 4,
.i_DoMaxdata = 0x0f,
- .interrupt = v_APCI3120_Interrupt,
+ .interrupt = apci3120_interrupt,
},
};
@@ -136,11 +136,11 @@ static int apci3120_auto_attach(struct comedi_device *dev,
s->len_chanlist = this_board->i_AiChannelList;
s->range_table = &range_apci3120_ai;
- s->insn_config = i_APCI3120_InsnConfigAnalogInput;
- s->insn_read = i_APCI3120_InsnReadAnalogInput;
- s->do_cmdtest = i_APCI3120_CommandTestAnalogInput;
- s->do_cmd = i_APCI3120_CommandAnalogInput;
- s->cancel = i_APCI3120_StopCyclicAcquisition;
+ s->insn_config = apci3120_ai_insn_config;
+ s->insn_read = apci3120_ai_insn_read;
+ s->do_cmdtest = apci3120_ai_cmdtest;
+ s->do_cmd = apci3120_ai_cmd;
+ s->cancel = apci3120_cancel;
/* Allocate and Initialise AO Subdevice Structures */
s = &dev->subdevices[1];
@@ -151,7 +151,7 @@ static int apci3120_auto_attach(struct comedi_device *dev,
s->maxdata = this_board->i_AoMaxdata;
s->len_chanlist = this_board->i_NbrAoChannel;
s->range_table = &range_apci3120_ao;
- s->insn_write = i_APCI3120_InsnWriteAnalogOutput;
+ s->insn_write = apci3120_ao_insn_write;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -186,11 +186,11 @@ static int apci3120_auto_attach(struct comedi_device *dev,
s->len_chanlist = 1;
s->range_table = &range_digital;
- s->insn_write = i_APCI3120_InsnWriteTimer;
- s->insn_read = i_APCI3120_InsnReadTimer;
- s->insn_config = i_APCI3120_InsnConfigTimer;
+ s->insn_write = apci3120_write_insn_timer;
+ s->insn_read = apci3120_read_insn_timer;
+ s->insn_config = apci3120_config_insn_timer;
- i_APCI3120_Reset(dev);
+ apci3120_reset(dev);
return 0;
}
@@ -200,7 +200,7 @@ static void apci3120_detach(struct comedi_device *dev)
if (devpriv) {
if (dev->iobase)
- i_APCI3120_Reset(dev);
+ apci3120_reset(dev);
if (dev->irq)
free_irq(dev->irq, dev);
if (devpriv->ul_DmaBufferVirtual[0]) {
@@ -230,7 +230,7 @@ static int apci3120_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &apci3120_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(apci3120_pci_table) = {
+static const struct pci_device_id apci3120_pci_table[] = {
{ PCI_VDEVICE(AMCC, 0x818d), BOARD_APCI3120 },
{ PCI_VDEVICE(AMCC, 0x828d), BOARD_APCI3001 },
{ 0 }
@@ -246,5 +246,5 @@ static struct pci_driver apci3120_pci_driver = {
module_comedi_pci_driver(apci3120_driver, apci3120_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("ADDI-DATA APCI-3120, Analog input board");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_3200.c b/drivers/staging/comedi/drivers/addi_apci_3200.c
index 1213d5aa6be..f0f891a482a 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3200.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3200.c
@@ -43,15 +43,15 @@ static const struct addi_board apci3200_boardtypes[] = {
.i_NbrDoChannel = 4,
.ui_MinAcquisitiontimeNs = 10000,
.ui_MinDelaytimeNs = 100000,
- .interrupt = v_APCI3200_Interrupt,
- .reset = i_APCI3200_Reset,
- .ai_config = i_APCI3200_ConfigAnalogInput,
- .ai_read = i_APCI3200_ReadAnalogInput,
- .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput,
- .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test,
- .ai_cmdtest = i_APCI3200_CommandTestAnalogInput,
- .ai_cmd = i_APCI3200_CommandAnalogInput,
- .ai_cancel = i_APCI3200_StopCyclicAcquisition,
+ .interrupt = apci3200_interrupt,
+ .reset = apci3200_reset,
+ .ai_config = apci3200_ai_config,
+ .ai_read = apci3200_ai_read,
+ .ai_write = apci3200_ai_write,
+ .ai_bits = apci3200_ai_bits_test,
+ .ai_cmdtest = apci3200_ai_cmdtest,
+ .ai_cmd = apci3200_ai_cmd,
+ .ai_cancel = apci3200_cancel,
.di_bits = apci3200_di_insn_bits,
.do_bits = apci3200_do_insn_bits,
},
@@ -68,15 +68,15 @@ static const struct addi_board apci3200_boardtypes[] = {
.i_NbrDoChannel = 4,
.ui_MinAcquisitiontimeNs = 10000,
.ui_MinDelaytimeNs = 100000,
- .interrupt = v_APCI3200_Interrupt,
- .reset = i_APCI3200_Reset,
- .ai_config = i_APCI3200_ConfigAnalogInput,
- .ai_read = i_APCI3200_ReadAnalogInput,
- .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput,
- .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test,
- .ai_cmdtest = i_APCI3200_CommandTestAnalogInput,
- .ai_cmd = i_APCI3200_CommandAnalogInput,
- .ai_cancel = i_APCI3200_StopCyclicAcquisition,
+ .interrupt = apci3200_interrupt,
+ .reset = apci3200_reset,
+ .ai_config = apci3200_ai_config,
+ .ai_read = apci3200_ai_read,
+ .ai_write = apci3200_ai_write,
+ .ai_bits = apci3200_ai_bits_test,
+ .ai_cmdtest = apci3200_ai_cmdtest,
+ .ai_cmd = apci3200_ai_cmd,
+ .ai_cancel = apci3200_cancel,
.di_bits = apci3200_di_insn_bits,
.do_bits = apci3200_do_insn_bits,
},
@@ -109,7 +109,7 @@ static int apci3200_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &apci3200_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(apci3200_pci_table) = {
+static const struct pci_device_id apci3200_pci_table[] = {
{ PCI_VDEVICE(ADDIDATA, 0x3000), BOARD_APCI3200 },
{ PCI_VDEVICE(ADDIDATA, 0x3007), BOARD_APCI3300 },
{ 0 }
diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c
index 6138440b919..49bf1fb840f 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3501.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3501.c
@@ -390,9 +390,9 @@ static int apci3501_auto_attach(struct comedi_device *dev,
s->maxdata = 0;
s->len_chanlist = 1;
s->range_table = &range_digital;
- s->insn_write = i_APCI3501_StartStopWriteTimerCounterWatchdog;
- s->insn_read = i_APCI3501_ReadTimerCounterWatchdog;
- s->insn_config = i_APCI3501_ConfigTimerCounterWatchdog;
+ s->insn_write = apci3501_write_insn_timer;
+ s->insn_read = apci3501_read_insn_timer;
+ s->insn_config = apci3501_config_insn_timer;
/* Initialize the eeprom subdevice */
s = &dev->subdevices[4];
@@ -428,7 +428,7 @@ static int apci3501_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &apci3501_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(apci3501_pci_table) = {
+static const struct pci_device_id apci3501_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3001) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
index 761cbf8f964..0532b6cc40e 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
@@ -373,7 +373,7 @@ static irqreturn_t apci3xxx_irq_handler(int irq, void *d)
writel(status, devpriv->mmio + 16);
val = readl(devpriv->mmio + 28);
- comedi_buf_put(s->async, val);
+ comedi_buf_put(s, val);
s->async->events |= COMEDI_CB_EOA;
comedi_event(dev, s);
@@ -434,13 +434,26 @@ static int apci3xxx_ai_setup(struct comedi_device *dev, unsigned int chanspec)
return 0;
}
+static int apci3xxx_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct apci3xxx_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readl(devpriv->mmio + 20);
+ if (status & 0x1)
+ return 0;
+ return -EBUSY;
+}
+
static int apci3xxx_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
struct apci3xxx_private *devpriv = dev->private;
- unsigned int val;
int ret;
int i;
@@ -453,10 +466,9 @@ static int apci3xxx_ai_insn_read(struct comedi_device *dev,
writel(0x80000, devpriv->mmio + 8);
/* Wait the EOS */
- do {
- val = readl(devpriv->mmio + 20);
- val &= 0x1;
- } while (!val);
+ ret = comedi_timeout(dev, s, insn, apci3xxx_ai_eoc, 0);
+ if (ret)
+ return ret;
/* Read the analog value */
data[i] = readl(devpriv->mmio + 28);
@@ -521,7 +533,7 @@ static int apci3xxx_ai_cmdtest(struct comedi_device *dev,
{
const struct apci3xxx_boardinfo *board = comedi_board(dev);
int err = 0;
- unsigned int tmp;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -561,31 +573,9 @@ static int apci3xxx_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
- /*
- * FIXME: The hardware supports multiple scan modes but the original
- * addi-data driver only supported reading a single channel with
- * interrupts. Need a proper datasheet to fix this.
- *
- * The following scan modes are supported by the hardware:
- * 1) Single software scan
- * 2) Single hardware triggered scan
- * 3) Continuous software scan
- * 4) Continuous software scan with timer delay
- * 5) Continuous hardware triggered scan
- * 6) Continuous hardware triggered scan with timer delay
- *
- * For now, limit the chanlist to a single channel.
- */
- if (cmd->chanlist_len > 1) {
- cmd->chanlist_len = 1;
- err |= -EINVAL;
- }
-
- tmp = cmd->convert_arg;
- err |= apci3xxx_ai_ns_to_timer(dev, &cmd->convert_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->convert_arg)
- err |= -EINVAL;
+ arg = cmd->convert_arg;
+ err |= apci3xxx_ai_ns_to_timer(dev, &arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
if (err)
return 4;
@@ -622,6 +612,20 @@ static int apci3xxx_ai_cancel(struct comedi_device *dev,
return 0;
}
+static int apci3xxx_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct apci3xxx_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readl(devpriv->mmio + 96);
+ if (status & 0x100)
+ return 0;
+ return -EBUSY;
+}
+
static int apci3xxx_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -630,7 +634,7 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev,
struct apci3xxx_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int range = CR_RANGE(insn->chanspec);
- unsigned int status;
+ int ret;
int i;
for (i = 0; i < insn->n; i++) {
@@ -641,9 +645,9 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev,
writel((data[i] << 8) | chan, devpriv->mmio + 100);
/* Wait the end of transfer */
- do {
- status = readl(devpriv->mmio + 96);
- } while ((status & 0x100) != 0x100);
+ ret = comedi_timeout(dev, s, insn, apci3xxx_ao_eoc, 0);
+ if (ret)
+ return ret;
}
return insn->n;
@@ -680,7 +684,7 @@ static int apci3xxx_dio_insn_config(struct comedi_device *dev,
unsigned int *data)
{
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int mask;
+ unsigned int mask = 0;
int ret;
/*
@@ -688,12 +692,14 @@ static int apci3xxx_dio_insn_config(struct comedi_device *dev,
* Port 1 (channels 8-15) are always outputs
* Port 2 (channels 16-23) are programmable i/o
*/
- if (chan < 16) {
- if (data[0] != INSN_CONFIG_DIO_QUERY)
+ if (data[0] != INSN_CONFIG_DIO_QUERY) {
+ /* ignore all other instructions for ports 0 and 1 */
+ if (chan < 16)
return -EINVAL;
- } else {
- /* changing any channel in port 2 changes the entire port */
- mask = 0xff0000;
+ else
+ /* changing any channel in port 2 */
+ /* changes the entire port */
+ mask = 0xff0000;
}
ret = comedi_dio_insn_config(dev, s, insn, data, mask);
@@ -815,12 +821,30 @@ static int apci3xxx_auto_attach(struct comedi_device *dev,
s->subdev_flags = SDF_READABLE | board->ai_subdev_flags;
s->n_chan = board->ai_n_chan;
s->maxdata = board->ai_maxdata;
- s->len_chanlist = s->n_chan;
s->range_table = &apci3xxx_ai_range;
s->insn_read = apci3xxx_ai_insn_read;
if (dev->irq) {
+ /*
+ * FIXME: The hardware supports multiple scan modes
+ * but the original addi-data driver only supported
+ * reading a single channel with interrupts. Need a
+ * proper datasheet to fix this.
+ *
+ * The following scan modes are supported by the
+ * hardware:
+ * 1) Single software scan
+ * 2) Single hardware triggered scan
+ * 3) Continuous software scan
+ * 4) Continuous software scan with timer delay
+ * 5) Continuous hardware triggered scan
+ * 6) Continuous hardware triggered scan with timer
+ * delay
+ *
+ * For now, limit the chanlist to a single channel.
+ */
dev->read_subdev = s;
s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = 1;
s->do_cmdtest = apci3xxx_ai_cmdtest;
s->do_cmd = apci3xxx_ai_cmd;
s->cancel = apci3xxx_ai_cancel;
@@ -915,7 +939,7 @@ static int apci3xxx_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &apci3xxx_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(apci3xxx_pci_table) = {
+static const struct pci_device_id apci3xxx_pci_table[] = {
{ PCI_VDEVICE(ADDIDATA, 0x3010), BOARD_APCI3000_16 },
{ PCI_VDEVICE(ADDIDATA, 0x300f), BOARD_APCI3000_8 },
{ PCI_VDEVICE(ADDIDATA, 0x300e), BOARD_APCI3000_4 },
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index dd092c7954a..921f6942dfc 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -73,19 +73,17 @@ struct pci6208_private {
unsigned int ao_readback[PCI6208_MAX_AO_CHANNELS];
};
-static int pci6208_ao_wait_for_data_send(struct comedi_device *dev,
- unsigned int timeout)
+static int pci6208_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
unsigned int status;
- while (timeout--) {
- status = inw(dev->iobase + PCI6208_AO_STATUS);
- if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0)
- return 0;
- udelay(1);
- }
-
- return -ETIME;
+ status = inw(dev->iobase + PCI6208_AO_STATUS);
+ if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0)
+ return 0;
+ return -EBUSY;
}
static int pci6208_ao_insn_write(struct comedi_device *dev,
@@ -102,8 +100,8 @@ static int pci6208_ao_insn_write(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
val = data[i];
- /* D/A transfer rate is 2.2us, wait up to 10us */
- ret = pci6208_ao_wait_for_data_send(dev, 10);
+ /* D/A transfer rate is 2.2us */
+ ret = comedi_timeout(dev, s, insn, pci6208_ao_eoc, 0);
if (ret)
return ret;
@@ -242,7 +240,7 @@ static int adl_pci6208_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(adl_pci6208_pci_table) = {
+static const struct pci_device_id adl_pci6208_pci_table[] = {
{ PCI_VDEVICE(ADLINK, 0x6208), BOARD_PCI6208 },
{ PCI_VDEVICE(ADLINK, 0x6216), BOARD_PCI6216 },
{ 0 }
diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c
index 5617f5ca384..5e3cc77a8a0 100644
--- a/drivers/staging/comedi/drivers/adl_pci7x3x.c
+++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c
@@ -239,9 +239,6 @@ static int adl_pci7x3x_auto_attach(struct comedi_device *dev,
}
}
- dev_info(dev->class_dev, "%s attached (%d inputs/%d outputs)\n",
- dev->board_name, board->di_nchan, board->do_nchan);
-
return 0;
}
@@ -259,7 +256,7 @@ static int adl_pci7x3x_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7x3x_pci_table) = {
+static const struct pci_device_id adl_pci7x3x_pci_table[] = {
{ PCI_VDEVICE(ADLINK, 0x7230), BOARD_PCI7230 },
{ PCI_VDEVICE(ADLINK, 0x7233), BOARD_PCI7233 },
{ PCI_VDEVICE(ADLINK, 0x7234), BOARD_PCI7234 },
diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c
index b3d009285ed..300df55a280 100644
--- a/drivers/staging/comedi/drivers/adl_pci8164.c
+++ b/drivers/staging/comedi/drivers/adl_pci8164.c
@@ -145,7 +145,7 @@ static int adl_pci8164_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
+static const struct pci_device_id adl_pci8164_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x8164) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index eab8da2c3d6..584fd57ecb7 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -84,7 +84,6 @@ TODO:
#define PCI9111_RANGE_SETTING_DELAY 10
#define PCI9111_AI_INSTANT_READ_UDELAY_US 2
-#define PCI9111_AI_INSTANT_READ_TIMEOUT 100
/*
* IO address map and bit defines
@@ -125,8 +124,7 @@ TODO:
PLX9052_INTCSR_LI2STAT)
static const struct comedi_lrange pci9111_ai_range = {
- 5,
- {
+ 5, {
BIP_RANGE(10),
BIP_RANGE(5),
BIP_RANGE(2.5),
@@ -139,10 +137,8 @@ struct pci9111_private_data {
unsigned long lcr_io_base;
int stop_counter;
- int stop_is_none;
unsigned int scan_delay;
- unsigned int chanlist_len;
unsigned int chunk_counter;
unsigned int chunk_num_samples;
@@ -316,148 +312,137 @@ static int pci9111_ai_cancel(struct comedi_device *dev,
return 0;
}
+static int pci9111_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
+ unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
+ int i;
+
+ for (i = 1; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+ unsigned int range = CR_RANGE(cmd->chanlist[i]);
+ unsigned int aref = CR_AREF(cmd->chanlist[i]);
+
+ if (chan != i) {
+ dev_dbg(dev->class_dev,
+ "entries in chanlist must be consecutive channels,counting upwards from 0\n");
+ return -EINVAL;
+ }
+
+ if (range != range0) {
+ dev_dbg(dev->class_dev,
+ "entries in chanlist must all have the same gain\n");
+ return -EINVAL;
+ }
+
+ if (aref != aref0) {
+ dev_dbg(dev->class_dev,
+ "entries in chanlist must all have the same reference\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int pci9111_ai_do_cmd_test(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
struct pci9111_private_data *dev_private = dev->private;
- int tmp;
- int error = 0;
- int range, reference;
- int i;
+ int err = 0;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
- error |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
- error |= cfc_check_trigger_src(&cmd->scan_begin_src,
+ err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+ err |= cfc_check_trigger_src(&cmd->scan_begin_src,
TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
- error |= cfc_check_trigger_src(&cmd->convert_src,
+ err |= cfc_check_trigger_src(&cmd->convert_src,
TRIG_TIMER | TRIG_EXT);
- error |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
- error |= cfc_check_trigger_src(&cmd->stop_src,
+ err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+ err |= cfc_check_trigger_src(&cmd->stop_src,
TRIG_COUNT | TRIG_NONE);
- if (error)
+ if (err)
return 1;
/* Step 2a : make sure trigger sources are unique */
- error |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
- error |= cfc_check_trigger_is_unique(cmd->convert_src);
- error |= cfc_check_trigger_is_unique(cmd->stop_src);
+ err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+ err |= cfc_check_trigger_is_unique(cmd->convert_src);
+ err |= cfc_check_trigger_is_unique(cmd->stop_src);
/* Step 2b : and mutually compatible */
- if ((cmd->convert_src == TRIG_TIMER) &&
- !((cmd->scan_begin_src == TRIG_TIMER) ||
- (cmd->scan_begin_src == TRIG_FOLLOW)))
- error |= -EINVAL;
- if ((cmd->convert_src == TRIG_EXT) &&
- !((cmd->scan_begin_src == TRIG_EXT) ||
- (cmd->scan_begin_src == TRIG_FOLLOW)))
- error |= -EINVAL;
+ if (cmd->scan_begin_src != TRIG_FOLLOW) {
+ if (cmd->scan_begin_src != cmd->convert_src)
+ err |= -EINVAL;
+ }
- if (error)
+ if (err)
return 2;
/* Step 3: check if arguments are trivially valid */
- error |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
if (cmd->convert_src == TRIG_TIMER)
- error |= cfc_check_trigger_arg_min(&cmd->convert_arg,
+ err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
PCI9111_AI_ACQUISITION_PERIOD_MIN_NS);
else /* TRIG_EXT */
- error |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
if (cmd->scan_begin_src == TRIG_TIMER)
- error |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
PCI9111_AI_ACQUISITION_PERIOD_MIN_NS);
else /* TRIG_FOLLOW || TRIG_EXT */
- error |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
- error |= cfc_check_trigger_arg_is(&cmd->scan_end_arg,
- cmd->chanlist_len);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
if (cmd->stop_src == TRIG_COUNT)
- error |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
+ err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
else /* TRIG_NONE */
- error |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
+ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
- if (error)
+ if (err)
return 3;
- /* Step 4 : fix up any arguments */
+ /* Step 4: fix up any arguments */
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
+ arg = cmd->convert_arg;
i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ,
&dev_private->div1,
&dev_private->div2,
- &cmd->convert_arg, cmd->flags);
- if (tmp != cmd->convert_arg)
- error++;
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
}
- /* There's only one timer on this card, so the scan_begin timer must */
- /* be a multiple of chanlist_len*convert_arg */
+ /*
+ * There's only one timer on this card, so the scan_begin timer
+ * must be a multiple of chanlist_len*convert_arg
+ */
if (cmd->scan_begin_src == TRIG_TIMER) {
+ arg = cmd->chanlist_len * cmd->convert_arg;
- unsigned int scan_begin_min;
- unsigned int scan_begin_arg;
- unsigned int scan_factor;
-
- scan_begin_min = cmd->chanlist_len * cmd->convert_arg;
-
- if (cmd->scan_begin_arg != scan_begin_min) {
- if (scan_begin_min < cmd->scan_begin_arg) {
- scan_factor =
- cmd->scan_begin_arg / scan_begin_min;
- scan_begin_arg = scan_factor * scan_begin_min;
- if (cmd->scan_begin_arg != scan_begin_arg) {
- cmd->scan_begin_arg = scan_begin_arg;
- error++;
- }
- } else {
- cmd->scan_begin_arg = scan_begin_min;
- error++;
- }
- }
+ if (arg < cmd->scan_begin_arg)
+ arg *= (cmd->scan_begin_arg / arg);
+
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
- if (error)
+ if (err)
return 4;
- /* Step 5 : check channel list */
-
- if (cmd->chanlist) {
-
- range = CR_RANGE(cmd->chanlist[0]);
- reference = CR_AREF(cmd->chanlist[0]);
-
- if (cmd->chanlist_len > 1) {
- for (i = 0; i < cmd->chanlist_len; i++) {
- if (CR_CHAN(cmd->chanlist[i]) != i) {
- comedi_error(dev,
- "entries in chanlist must be consecutive "
- "channels,counting upwards from 0\n");
- error++;
- }
- if (CR_RANGE(cmd->chanlist[i]) != range) {
- comedi_error(dev,
- "entries in chanlist must all have the same gain\n");
- error++;
- }
- if (CR_AREF(cmd->chanlist[i]) != reference) {
- comedi_error(dev,
- "entries in chanlist must all have the same reference\n");
- error++;
- }
- }
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= pci9111_ai_check_chanlist(dev, s, cmd);
- if (error)
+ if (err)
return 5;
return 0;
@@ -468,23 +453,18 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct pci9111_private_data *dev_private = dev->private;
- struct comedi_cmd *async_cmd = &s->async->cmd;
+ struct comedi_cmd *cmd = &s->async->cmd;
- if (!dev->irq) {
- comedi_error(dev,
- "no irq assigned for PCI9111, cannot do hardware conversion");
- return -1;
- }
/* Set channel scan limit */
/* PCI9111 allows only scanning from channel 0 to channel n */
/* TODO: handle the case of an external multiplexer */
- if (async_cmd->chanlist_len > 1) {
- outb(async_cmd->chanlist_len - 1,
+ if (cmd->chanlist_len > 1) {
+ outb(cmd->chanlist_len - 1,
dev->iobase + PCI9111_AI_CHANNEL_REG);
pci9111_autoscan_set(dev, true);
} else {
- outb(CR_CHAN(async_cmd->chanlist[0]),
+ outb(CR_CHAN(cmd->chanlist[0]),
dev->iobase + PCI9111_AI_CHANNEL_REG);
pci9111_autoscan_set(dev, false);
}
@@ -492,33 +472,18 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev,
/* Set gain */
/* This is the same gain on every channel */
- outb(CR_RANGE(async_cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK,
+ outb(CR_RANGE(cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK,
dev->iobase + PCI9111_AI_RANGE_STAT_REG);
/* Set counter */
-
- switch (async_cmd->stop_src) {
- case TRIG_COUNT:
- dev_private->stop_counter =
- async_cmd->stop_arg * async_cmd->chanlist_len;
- dev_private->stop_is_none = 0;
- break;
-
- case TRIG_NONE:
+ if (cmd->stop_src == TRIG_COUNT)
+ dev_private->stop_counter = cmd->stop_arg * cmd->chanlist_len;
+ else /* TRIG_NONE */
dev_private->stop_counter = 0;
- dev_private->stop_is_none = 1;
- break;
-
- default:
- comedi_error(dev, "Invalid stop trigger");
- return -1;
- }
/* Set timer pacer */
-
dev_private->scan_delay = 0;
- switch (async_cmd->convert_src) {
- case TRIG_TIMER:
+ if (cmd->convert_src == TRIG_TIMER) {
pci9111_trigger_source_set(dev, software);
pci9111_timer_set(dev);
pci9111_fifo_reset(dev);
@@ -528,17 +493,11 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev,
plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
false, true, true);
- if (async_cmd->scan_begin_src == TRIG_TIMER) {
- dev_private->scan_delay =
- (async_cmd->scan_begin_arg /
- (async_cmd->convert_arg *
- async_cmd->chanlist_len)) - 1;
+ if (cmd->scan_begin_src == TRIG_TIMER) {
+ dev_private->scan_delay = (cmd->scan_begin_arg /
+ (cmd->convert_arg * cmd->chanlist_len)) - 1;
}
-
- break;
-
- case TRIG_EXT:
-
+ } else { /* TRIG_EXT */
pci9111_trigger_source_set(dev, external);
pci9111_fifo_reset(dev);
pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
@@ -546,18 +505,12 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev,
plx9050_interrupt_control(dev_private->lcr_io_base, true, true,
false, true, true);
- break;
-
- default:
- comedi_error(dev, "Invalid convert trigger");
- return -1;
}
dev_private->stop_counter *= (1 + dev_private->scan_delay);
- dev_private->chanlist_len = async_cmd->chanlist_len;
dev_private->chunk_counter = 0;
- dev_private->chunk_num_samples =
- dev_private->chanlist_len * (1 + dev_private->scan_delay);
+ dev_private->chunk_num_samples = cmd->chanlist_len *
+ (1 + dev_private->scan_delay);
return 0;
}
@@ -578,12 +531,71 @@ static void pci9111_ai_munge(struct comedi_device *dev,
array[i] = ((array[i] >> shift) & maxdata) ^ invert;
}
+static void pci9111_handle_fifo_half_full(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct pci9111_private_data *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int total = 0;
+ unsigned int samples;
+
+ if (cmd->stop_src == TRIG_COUNT &&
+ PCI9111_FIFO_HALF_SIZE > devpriv->stop_counter)
+ samples = devpriv->stop_counter;
+ else
+ samples = PCI9111_FIFO_HALF_SIZE;
+
+ insw(dev->iobase + PCI9111_AI_FIFO_REG,
+ devpriv->ai_bounce_buffer, samples);
+
+ if (devpriv->scan_delay < 1) {
+ total = cfc_write_array_to_buffer(s,
+ devpriv->ai_bounce_buffer,
+ samples * sizeof(short));
+ } else {
+ unsigned int pos = 0;
+ unsigned int to_read;
+
+ while (pos < samples) {
+ if (devpriv->chunk_counter < cmd->chanlist_len) {
+ to_read = cmd->chanlist_len -
+ devpriv->chunk_counter;
+
+ if (to_read > samples - pos)
+ to_read = samples - pos;
+
+ total += cfc_write_array_to_buffer(s,
+ devpriv->ai_bounce_buffer + pos,
+ to_read * sizeof(short));
+ } else {
+ to_read = devpriv->chunk_num_samples -
+ devpriv->chunk_counter;
+
+ if (to_read > samples - pos)
+ to_read = samples - pos;
+
+ total += to_read * sizeof(short);
+ }
+
+ pos += to_read;
+ devpriv->chunk_counter += to_read;
+
+ if (devpriv->chunk_counter >=
+ devpriv->chunk_num_samples)
+ devpriv->chunk_counter = 0;
+ }
+ }
+
+ devpriv->stop_counter -= total / sizeof(short);
+}
+
static irqreturn_t pci9111_interrupt(int irq, void *p_device)
{
struct comedi_device *dev = p_device;
struct pci9111_private_data *dev_private = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async;
+ struct comedi_cmd *cmd;
unsigned int status;
unsigned long irq_flags;
unsigned char intcsr;
@@ -595,6 +607,7 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device)
}
async = s->async;
+ cmd = &async->cmd;
spin_lock_irqsave(&dev->spinlock, irq_flags);
@@ -619,100 +632,42 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device)
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow");
outb(0, dev->iobase + PCI9111_INT_CLR_REG);
- pci9111_ai_cancel(dev, s);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
/* '0' means FIFO is half-full */
- if (!(status & PCI9111_AI_STAT_FF_HF)) {
- unsigned int num_samples;
- unsigned int bytes_written = 0;
-
- num_samples =
- PCI9111_FIFO_HALF_SIZE >
- dev_private->stop_counter
- && !dev_private->
- stop_is_none ? dev_private->stop_counter :
- PCI9111_FIFO_HALF_SIZE;
- insw(dev->iobase + PCI9111_AI_FIFO_REG,
- dev_private->ai_bounce_buffer, num_samples);
-
- if (dev_private->scan_delay < 1) {
- bytes_written =
- cfc_write_array_to_buffer(s,
- dev_private->
- ai_bounce_buffer,
- num_samples *
- sizeof(short));
- } else {
- int position = 0;
- int to_read;
-
- while (position < num_samples) {
- if (dev_private->chunk_counter <
- dev_private->chanlist_len) {
- to_read =
- dev_private->chanlist_len -
- dev_private->chunk_counter;
-
- if (to_read >
- num_samples - position)
- to_read =
- num_samples -
- position;
-
- bytes_written +=
- cfc_write_array_to_buffer
- (s,
- dev_private->ai_bounce_buffer
- + position,
- to_read * sizeof(short));
- } else {
- to_read =
- dev_private->chunk_num_samples
- -
- dev_private->chunk_counter;
- if (to_read >
- num_samples - position)
- to_read =
- num_samples -
- position;
-
- bytes_written +=
- sizeof(short) * to_read;
- }
-
- position += to_read;
- dev_private->chunk_counter += to_read;
-
- if (dev_private->chunk_counter >=
- dev_private->chunk_num_samples)
- dev_private->chunk_counter = 0;
- }
- }
-
- dev_private->stop_counter -=
- bytes_written / sizeof(short);
- }
+ if (!(status & PCI9111_AI_STAT_FF_HF))
+ pci9111_handle_fifo_half_full(dev, s);
}
- if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) {
+ if (cmd->stop_src == TRIG_COUNT && dev_private->stop_counter == 0)
async->events |= COMEDI_CB_EOA;
- pci9111_ai_cancel(dev, s);
- }
outb(0, dev->iobase + PCI9111_INT_CLR_REG);
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
+static int pci9111_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
+ if (status & PCI9111_AI_STAT_FF_EF)
+ return 0;
+ return -EBUSY;
+}
+
static int pci9111_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -723,7 +678,7 @@ static int pci9111_ai_insn_read(struct comedi_device *dev,
unsigned int invert = (maxdata + 1) >> 1;
unsigned int shift = (maxdata == 0xffff) ? 0 : 4;
unsigned int status;
- int timeout;
+ int ret;
int i;
outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG);
@@ -740,22 +695,12 @@ static int pci9111_ai_insn_read(struct comedi_device *dev,
/* Generate a software trigger */
outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG);
- timeout = PCI9111_AI_INSTANT_READ_TIMEOUT;
-
- while (timeout--) {
- status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
- /* '1' means FIFO is not empty */
- if (status & PCI9111_AI_STAT_FF_EF)
- goto conversion_done;
+ ret = comedi_timeout(dev, s, insn, pci9111_ai_eoc, 0);
+ if (ret) {
+ pci9111_fifo_reset(dev);
+ return ret;
}
- comedi_error(dev, "A/D read timeout");
- data[i] = 0;
- pci9111_fifo_reset(dev);
- return -ETIME;
-
-conversion_done:
-
data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG);
data[i] = ((data[i] >> shift) & maxdata) ^ invert;
}
@@ -858,12 +803,11 @@ static int pci9111_auto_attach(struct comedi_device *dev,
pci9111_reset(dev);
- if (pcidev->irq > 0) {
- ret = request_irq(dev->irq, pci9111_interrupt,
+ if (pcidev->irq) {
+ ret = request_irq(pcidev->irq, pci9111_interrupt,
IRQF_SHARED, dev->board_name, dev);
- if (ret)
- return ret;
- dev->irq = pcidev->irq;
+ if (ret == 0)
+ dev->irq = pcidev->irq;
}
ret = comedi_alloc_subdevices(dev, 4);
@@ -871,18 +815,21 @@ static int pci9111_auto_attach(struct comedi_device *dev,
return ret;
s = &dev->subdevices[0];
- dev->read_subdev = s;
s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
+ s->subdev_flags = SDF_READABLE | SDF_COMMON;
s->n_chan = 16;
s->maxdata = 0xffff;
- s->len_chanlist = 16;
s->range_table = &pci9111_ai_range;
- s->cancel = pci9111_ai_cancel;
s->insn_read = pci9111_ai_insn_read;
- s->do_cmdtest = pci9111_ai_do_cmd_test;
- s->do_cmd = pci9111_ai_do_cmd;
- s->munge = pci9111_ai_munge;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = s->n_chan;
+ s->do_cmdtest = pci9111_ai_do_cmd_test;
+ s->do_cmd = pci9111_ai_do_cmd;
+ s->cancel = pci9111_ai_cancel;
+ s->munge = pci9111_ai_munge;
+ }
s = &dev->subdevices[1];
s->type = COMEDI_SUBD_AO;
@@ -910,8 +857,6 @@ static int pci9111_auto_attach(struct comedi_device *dev,
s->range_table = &range_digital;
s->insn_bits = pci9111_do_insn_bits;
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
@@ -938,7 +883,7 @@ static int pci9111_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
+static const struct pci_device_id pci9111_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
/* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
{ 0 }
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index 986489641ed..59a65cbc6db 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -96,7 +96,7 @@ Configuration options:
* correct channel number on every 12 bit sample
*/
-#define IORANGE_9118 64 /* I hope */
+#define IORANGE_9118 64 /* I hope */
#define PCI9118_CHANLEN 255 /*
* len of chanlist, some source say 256,
* but reality looks like 255 :-(
@@ -194,28 +194,30 @@ Configuration options:
#define EXTTRG_AI 0 /* ext trg is used by AI */
-static const struct comedi_lrange range_pci9118dg_hr = { 8, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25)
- }
+static const struct comedi_lrange range_pci9118dg_hr = {
+ 8, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
-static const struct comedi_lrange range_pci9118hg = { 8, {
- BIP_RANGE(5),
- BIP_RANGE(0.5),
- BIP_RANGE(0.05),
- BIP_RANGE(0.005),
- UNI_RANGE(10),
- UNI_RANGE(1),
- UNI_RANGE(0.1),
- UNI_RANGE(0.01)
- }
+static const struct comedi_lrange range_pci9118hg = {
+ 8, {
+ BIP_RANGE(5),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.05),
+ BIP_RANGE(0.005),
+ UNI_RANGE(10),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1),
+ UNI_RANGE(0.01)
+ }
};
#define PCI9118_BIPOLAR_RANGES 4 /*
@@ -318,14 +320,9 @@ struct pci9118_private {
unsigned char AdControlReg; /* A/D control register */
unsigned char IntControlReg; /* Interrupt control register */
unsigned char AdFunctionReg; /* A/D function register */
- char valid; /* driver is ok */
char ai_neverending; /* we do unlimited AI */
- unsigned int i8254_osc_base; /* frequence of onboard oscilator */
unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */
unsigned int ai_act_scan; /* how many scans we finished */
- unsigned int ai_buf_ptr; /* data buffer ptr in samples */
- unsigned int ai_n_chan; /* how many channels is measured */
- unsigned int ai_n_scanlen; /* len of actual scanlist */
unsigned int ai_n_realscanlen; /*
* what we must transfer for one
* outgoing scan include front/back adds
@@ -339,9 +336,6 @@ struct pci9118_private {
* how many channels we must add
* before scan to satisfy DMA?
*/
- unsigned int *ai_chanlist; /* actual chanlist */
- unsigned int ai_timer1;
- unsigned int ai_timer2;
unsigned int ai_flags;
char ai12_startstop; /*
* measure can start/stop
@@ -351,9 +345,7 @@ struct pci9118_private {
* divisors for start of measure
* on external start
*/
- unsigned int ai_data_len;
unsigned short ao_data[2]; /* data output buffer */
- unsigned int ai_scans; /* number of scans to do */
char dma_doublebuf; /* we can use double buffering */
unsigned int dma_actbuf; /* which buffer is used now */
unsigned short *dmabuf_virt[2]; /*
@@ -370,31 +362,12 @@ struct pci9118_private {
*/
unsigned int dmabuf_used_size[2]; /* which size was truly used */
unsigned int dmabuf_panic_size[2];
- unsigned int dmabuf_samples[2]; /* size in samples */
int dmabuf_pages[2]; /* number of pages in buffer */
- unsigned char cnt0_users; /*
- * bit field of 8254 CNT0 users
- * (0-unused, 1-AO, 2-DI, 3-DO)
- */
unsigned char exttrg_users; /*
* bit field of external trigger
* users(0-AI, 1-AO, 2-DI, 3-DO)
*/
- unsigned int cnt0_divisor; /* actual CNT0 divisor */
- void (*int_ai_func) (struct comedi_device *, struct comedi_subdevice *,
- unsigned short,
- unsigned int,
- unsigned short); /*
- * ptr to actual interrupt
- * AI function
- */
- unsigned char ai16bits; /* =1 16 bit card */
unsigned char usedma; /* =1 use DMA transfer and not INT */
- unsigned char useeoshandle; /*
- * =1 change WAKE_EOS DMA transfer
- * to fit on every second
- */
- unsigned char usessh; /* =1 turn on S&H support */
int softsshdelay; /*
* >0 use software S&H,
* numer is requested delay in ns
@@ -409,7 +382,6 @@ struct pci9118_private {
*/
unsigned int ai_maskerr; /* which warning was printed */
unsigned int ai_maskharderr; /* on which error bits stops */
- unsigned int ai_inttrig_start; /* TRIG_INT for start */
};
static int check_channel_list(struct comedi_device *dev,
@@ -466,7 +438,7 @@ static int check_channel_list(struct comedi_device *dev,
static int setup_channel_list(struct comedi_device *dev,
struct comedi_subdevice *s, int n_chan,
unsigned int *chanlist, int rot, int frontadd,
- int backadd, int usedma, char useeos)
+ int backadd, int usedma)
{
struct pci9118_private *devpriv = dev->private;
unsigned int i, differencial = 0, bipolar = 0;
@@ -550,18 +522,6 @@ static int setup_channel_list(struct comedi_device *dev,
#ifdef PCI9118_PARANOIDCHECK
devpriv->chanlist[n_chan ^ usedma] = devpriv->chanlist[0 ^ usedma];
/* for 32bit operations */
- if (useeos) {
- for (i = 1; i < n_chan; i++) { /* store range list to card */
- devpriv->chanlist[(n_chan + i) ^ usedma] =
- (CR_CHAN(chanlist[i]) & 0xf) << rot;
- }
- devpriv->chanlist[(2 * n_chan) ^ usedma] =
- devpriv->chanlist[0 ^ usedma];
- /* for 32bit operations */
- useeos = 2;
- } else {
- useeos = 1;
- }
#endif
outl(0, dev->iobase + PCI9118_SCANMOD); /* close scan queue */
/* udelay(100); important delay, or first sample will be crippled */
@@ -569,12 +529,26 @@ static int setup_channel_list(struct comedi_device *dev,
return 1; /* we can serve this with scan logic */
}
+static int pci9118_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inl(dev->iobase + PCI9118_ADSTAT);
+ if (status & AdStatus_ADrdy)
+ return 0;
+ return -EBUSY;
+}
+
static int pci9118_insn_read_ai(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct pci9118_private *devpriv = dev->private;
- int n, timeout;
+ int ret;
+ int n;
devpriv->AdControlReg = AdControl_Int & 0xff;
devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg;
@@ -587,7 +561,7 @@ static int pci9118_insn_read_ai(struct comedi_device *dev,
* trigger stop
*/
- if (!setup_channel_list(dev, s, 1, &insn->chanspec, 0, 0, 0, 0, 0))
+ if (!setup_channel_list(dev, s, 1, &insn->chanspec, 0, 0, 0, 0))
return -EINVAL;
outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
@@ -595,20 +569,14 @@ static int pci9118_insn_read_ai(struct comedi_device *dev,
for (n = 0; n < insn->n; n++) {
outw(0, dev->iobase + PCI9118_SOFTTRG); /* start conversion */
udelay(2);
- timeout = 100;
- while (timeout--) {
- if (inl(dev->iobase + PCI9118_ADSTAT) & AdStatus_ADrdy)
- goto conv_finish;
- udelay(1);
- }
- comedi_error(dev, "A/D insn timeout");
- data[n] = 0;
- outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
- return -ETIME;
+ ret = comedi_timeout(dev, s, insn, pci9118_ai_eoc, 0);
+ if (ret) {
+ outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
+ return ret;
+ }
-conv_finish:
- if (devpriv->ai16bits) {
+ if (s->maxdata == 0xffff) {
data[n] =
(inl(dev->iobase +
PCI9118_AD_DATA) & 0xffff) ^ 0x8000;
@@ -703,10 +671,11 @@ static unsigned int defragment_dma_buffer(struct comedi_device *dev,
unsigned int num_samples)
{
struct pci9118_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned int i = 0, j = 0;
unsigned int start_pos = devpriv->ai_add_front,
- stop_pos = devpriv->ai_add_front + devpriv->ai_n_chan;
- unsigned int raw_scanlen = devpriv->ai_add_front + devpriv->ai_n_chan +
+ stop_pos = devpriv->ai_add_front + cmd->chanlist_len;
+ unsigned int raw_scanlen = devpriv->ai_add_front + cmd->chanlist_len +
devpriv->ai_add_back;
for (i = 0; i < num_samples; i++) {
@@ -727,13 +696,14 @@ static int move_block_from_dma(struct comedi_device *dev,
unsigned int num_samples)
{
struct pci9118_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned int num_bytes;
num_samples = defragment_dma_buffer(dev, s, dma_buffer, num_samples);
devpriv->ai_act_scan +=
- (s->async->cur_chan + num_samples) / devpriv->ai_n_scanlen;
+ (s->async->cur_chan + num_samples) / cmd->scan_end_arg;
s->async->cur_chan += num_samples;
- s->async->cur_chan %= devpriv->ai_n_scanlen;
+ s->async->cur_chan %= cmd->scan_end_arg;
num_bytes =
cfc_write_array_to_buffer(s, dma_buffer,
num_samples * sizeof(short));
@@ -781,47 +751,51 @@ static void pci9118_calc_divisors(char mode, struct comedi_device *dev,
unsigned int *tim1, unsigned int *tim2,
unsigned int flags, int chans,
unsigned int *div1, unsigned int *div2,
- char usessh, unsigned int chnsshfront)
+ unsigned int chnsshfront)
{
const struct boardtype *this_board = comedi_board(dev);
- struct pci9118_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
switch (mode) {
case 1:
case 4:
if (*tim2 < this_board->ai_ns_min)
*tim2 = this_board->ai_ns_min;
- i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
div1, div2,
tim2, flags & TRIG_ROUND_NEAREST);
break;
case 2:
if (*tim2 < this_board->ai_ns_min)
*tim2 = this_board->ai_ns_min;
- *div1 = *tim2 / devpriv->i8254_osc_base;
+ *div1 = *tim2 / I8254_OSC_BASE_4MHZ;
/* convert timer (burst) */
if (*div1 < this_board->ai_pacer_min)
*div1 = this_board->ai_pacer_min;
- *div2 = *tim1 / devpriv->i8254_osc_base; /* scan timer */
+ *div2 = *tim1 / I8254_OSC_BASE_4MHZ; /* scan timer */
*div2 = *div2 / *div1; /* major timer is c1*c2 */
if (*div2 < chans)
*div2 = chans;
- *tim2 = *div1 * devpriv->i8254_osc_base;
- /* real convert timer */
+ *tim2 = *div1 * I8254_OSC_BASE_4MHZ; /* real convert timer */
- if (usessh && (chnsshfront == 0)) /* use BSSH signal */
+ if (cmd->convert_src == TRIG_NOW && !chnsshfront) {
+ /* use BSSH signal */
if (*div2 < (chans + 2))
*div2 = chans + 2;
+ }
- *tim1 = *div1 * *div2 * devpriv->i8254_osc_base;
+ *tim1 = *div1 * *div2 * I8254_OSC_BASE_4MHZ;
break;
}
}
-static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2)
+static void pci9118_start_pacer(struct comedi_device *dev, int mode)
{
+ struct pci9118_private *devpriv = dev->private;
+ unsigned int divisor1 = devpriv->ai_divisor1;
+ unsigned int divisor2 = devpriv->ai_divisor2;
+
outl(0x74, dev->iobase + PCI9118_CNTCTRL);
outl(0xb4, dev->iobase + PCI9118_CNTCTRL);
/* outl(0x30, dev->iobase + PCI9118_CNTCTRL); */
@@ -845,7 +819,7 @@ static int pci9118_ai_cancel(struct comedi_device *dev,
(~EN_A2P_TRANSFERS),
devpriv->iobase_a + AMCC_OP_REG_MCSR); /* stop DMA */
pci9118_exttrg_del(dev, EXTTRG_AI);
- start_pacer(dev, 0, 0, 0); /* stop 8254 counters */
+ pci9118_start_pacer(dev, 0); /* stop 8254 counters */
devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg;
outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
/*
@@ -872,7 +846,6 @@ static int pci9118_ai_cancel(struct comedi_device *dev,
devpriv->ai_act_dmapos = 0;
s->async->cur_chan = 0;
s->async->inttrig = NULL;
- devpriv->ai_buf_ptr = 0;
devpriv->ai_neverending = 0;
devpriv->dma_actbuf = 0;
@@ -909,8 +882,7 @@ static char pci9118_decode_error_status(struct comedi_device *dev,
}
if (m & devpriv->ai_maskharderr) {
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- pci9118_ai_cancel(dev, s);
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return 1;
}
@@ -929,7 +901,7 @@ static void pci9118_ai_munge(struct comedi_device *dev,
for (i = 0; i < num_samples; i++) {
if (devpriv->usedma)
array[i] = be16_to_cpu(array[i]);
- if (devpriv->ai16bits)
+ if (s->maxdata == 0xffff)
array[i] ^= 0x8000;
else
array[i] = (array[i] >> 4) & 0x0fff;
@@ -944,10 +916,9 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev,
unsigned short int_daq)
{
struct pci9118_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned short sampl;
- s->async->events = 0;
-
if (int_adstat & devpriv->ai_maskerr)
if (pci9118_decode_error_status(dev, s, int_adstat))
return;
@@ -955,7 +926,7 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev,
sampl = inw(dev->iobase + PCI9118_AD_DATA);
#ifdef PCI9118_PARANOIDCHECK
- if (devpriv->ai16bits == 0) {
+ if (s->maxdata != 0xffff) {
if ((sampl & 0x000f) != devpriv->chanlist[s->async->cur_chan]) {
/* data dropout! */
dev_info(dev->class_dev,
@@ -963,28 +934,25 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev,
sampl & 0x000f,
devpriv->chanlist[s->async->cur_chan]);
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- pci9118_ai_cancel(dev, s);
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
}
#endif
cfc_write_to_buffer(s, sampl);
s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_scanlen) {
+ if (s->async->cur_chan >= cmd->scan_end_arg) {
/* one scan done */
- s->async->cur_chan %= devpriv->ai_n_scanlen;
+ s->async->cur_chan %= cmd->scan_end_arg;
devpriv->ai_act_scan++;
- if (!(devpriv->ai_neverending))
- if (devpriv->ai_act_scan >= devpriv->ai_scans) {
- /* all data sampled */
- pci9118_ai_cancel(dev, s);
+ if (!devpriv->ai_neverending) {
+ /* all data sampled? */
+ if (devpriv->ai_act_scan >= cmd->stop_arg)
s->async->events |= COMEDI_CB_EOA;
- }
+ }
}
- if (s->async->events)
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
@@ -994,21 +962,20 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
unsigned short int_daq)
{
struct pci9118_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned int next_dma_buf, samplesinbuf, sampls, m;
if (int_amcc & MASTER_ABORT_INT) {
comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- pci9118_ai_cancel(dev, s);
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
if (int_amcc & TARGET_ABORT_INT) {
comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- pci9118_ai_cancel(dev, s);
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
if (int_adstat & devpriv->ai_maskerr)
@@ -1035,23 +1002,20 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
}
if (samplesinbuf) {
- m = devpriv->ai_data_len >> 1; /*
- * how many samples is to
- * end of buffer
- */
+ /* how many samples is to end of buffer */
+ m = s->async->prealloc_bufsz >> 1;
sampls = m;
move_block_from_dma(dev, s,
devpriv->dmabuf_virt[devpriv->dma_actbuf],
samplesinbuf);
- m = m - sampls; /* m= how many samples was transferred */
+ m = m - sampls; /* m=how many samples was transferred */
}
- if (!devpriv->ai_neverending)
- if (devpriv->ai_act_scan >= devpriv->ai_scans) {
- /* all data sampled */
- pci9118_ai_cancel(dev, s);
+ if (!devpriv->ai_neverending) {
+ /* all data sampled? */
+ if (devpriv->ai_act_scan >= cmd->stop_arg)
s->async->events |= COMEDI_CB_EOA;
- }
+ }
if (devpriv->dma_doublebuf) { /* switch dma buffers */
devpriv->dma_actbuf = 1 - devpriv->dma_actbuf;
@@ -1064,81 +1028,74 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
interrupt_pci9118_ai_mode4_switch(dev);
}
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
-static irqreturn_t interrupt_pci9118(int irq, void *d)
+static irqreturn_t pci9118_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
+ struct comedi_subdevice *s = dev->read_subdev;
struct pci9118_private *devpriv = dev->private;
- unsigned int int_daq = 0, int_amcc, int_adstat;
+ unsigned int intsrc; /* IRQ reasons from card */
+ unsigned int intcsr; /* INT register from AMCC chip */
+ unsigned int adstat; /* STATUS register */
if (!dev->attached)
- return IRQ_NONE; /* not fully initialized */
-
- int_daq = inl(dev->iobase + PCI9118_INTSRC) & 0xf;
- /* get IRQ reasons from card */
- int_amcc = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR);
- /* get INT register from AMCC chip */
-
- if ((!int_daq) && (!(int_amcc & ANY_S593X_INT)))
- return IRQ_NONE; /* interrupt from other source */
-
- outl(int_amcc | 0x00ff0000, devpriv->iobase_a + AMCC_OP_REG_INTCSR);
- /* shutdown IRQ reasons in AMCC */
-
- int_adstat = inw(dev->iobase + PCI9118_ADSTAT) & 0x1ff;
- /* get STATUS register */
-
- if (devpriv->ai_do) {
- if (devpriv->ai12_startstop)
- if ((int_adstat & AdStatus_DTH) &&
- (int_daq & Int_DTrg)) {
- /* start stop of measure */
- if (devpriv->ai12_startstop & START_AI_EXT) {
- devpriv->ai12_startstop &=
- ~START_AI_EXT;
- if (!(devpriv->ai12_startstop &
- STOP_AI_EXT))
- pci9118_exttrg_del
- (dev, EXTTRG_AI);
- /* deactivate EXT trigger */
- start_pacer(dev, devpriv->ai_do,
- devpriv->ai_divisor1,
- devpriv->ai_divisor2);
- /* start pacer */
- outl(devpriv->AdControlReg,
- dev->iobase + PCI9118_ADCNTRL);
- } else {
- if (devpriv->ai12_startstop &
- STOP_AI_EXT) {
- devpriv->ai12_startstop &=
- ~STOP_AI_EXT;
- pci9118_exttrg_del
- (dev, EXTTRG_AI);
- /* deactivate EXT trigger */
- devpriv->ai_neverending = 0;
- /*
- * well, on next interrupt from
- * DMA/EOC measure will stop
- */
- }
- }
- }
+ return IRQ_NONE;
+
+ intsrc = inl(dev->iobase + PCI9118_INTSRC) & 0xf;
+ intcsr = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR);
- (devpriv->int_ai_func) (dev, &dev->subdevices[0], int_adstat,
- int_amcc, int_daq);
+ if (!intsrc && !(intcsr & ANY_S593X_INT))
+ return IRQ_NONE;
+ outl(intcsr | 0x00ff0000, devpriv->iobase_a + AMCC_OP_REG_INTCSR);
+
+ adstat = inw(dev->iobase + PCI9118_ADSTAT) & 0x1ff;
+
+ if (!devpriv->ai_do)
+ return IRQ_HANDLED;
+
+ if (devpriv->ai12_startstop) {
+ if ((adstat & AdStatus_DTH) && (intsrc & Int_DTrg)) {
+ /* start/stop of measure */
+ if (devpriv->ai12_startstop & START_AI_EXT) {
+ /* deactivate EXT trigger */
+ devpriv->ai12_startstop &= ~START_AI_EXT;
+ if (!(devpriv->ai12_startstop & STOP_AI_EXT))
+ pci9118_exttrg_del(dev, EXTTRG_AI);
+
+ /* start pacer */
+ pci9118_start_pacer(dev, devpriv->ai_do);
+ outl(devpriv->AdControlReg,
+ dev->iobase + PCI9118_ADCNTRL);
+ } else if (devpriv->ai12_startstop & STOP_AI_EXT) {
+ /* deactivate EXT trigger */
+ devpriv->ai12_startstop &= ~STOP_AI_EXT;
+ pci9118_exttrg_del(dev, EXTTRG_AI);
+
+ /* on next interrupt measure will stop */
+ devpriv->ai_neverending = 0;
+ }
+ }
}
+
+ if (devpriv->usedma)
+ interrupt_pci9118_ai_dma(dev, s, adstat, intcsr, intsrc);
+ else
+ interrupt_pci9118_ai_onesample(dev, s, adstat, intcsr, intsrc);
+
return IRQ_HANDLED;
}
static int pci9118_ai_inttrig(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int trignum)
+ struct comedi_subdevice *s,
+ unsigned int trig_num)
{
struct pci9118_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
- if (trignum != devpriv->ai_inttrig_start)
+ if (trig_num != cmd->start_arg)
return -EINVAL;
devpriv->ai12_startstop &= ~START_AI_INT;
@@ -1147,8 +1104,7 @@ static int pci9118_ai_inttrig(struct comedi_device *dev,
outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
if (devpriv->ai_do != 3) {
- start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1,
- devpriv->ai_divisor2);
+ pci9118_start_pacer(dev, devpriv->ai_do);
devpriv->AdControlReg |= AdControl_SoftG;
}
outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
@@ -1164,7 +1120,7 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev,
struct pci9118_private *devpriv = dev->private;
int err = 0;
unsigned int flags;
- int tmp;
+ unsigned int arg;
unsigned int divisor1 = 0, divisor2 = 0;
/* Step 1 : check if triggers are trivially valid */
@@ -1220,8 +1176,15 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev,
/* Step 3: check if arguments are trivially valid */
- if (cmd->start_src & (TRIG_NOW | TRIG_EXT))
+ switch (cmd->start_src) {
+ case TRIG_NOW:
+ case TRIG_EXT:
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ break;
+ case TRIG_INT:
+ /* start_arg is the internal trigger (any value) */
+ break;
+ }
if (cmd->scan_begin_src & (TRIG_FOLLOW | TRIG_EXT))
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
@@ -1258,8 +1221,6 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
- err |= cfc_check_trigger_arg_max(&cmd->chanlist_len,
- this_board->n_aichanlist);
err |= cfc_check_trigger_arg_min(&cmd->scan_end_arg,
cmd->chanlist_len);
@@ -1276,45 +1237,30 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
- i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,
+ arg = cmd->scan_begin_arg;
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
&divisor1, &divisor2,
- &cmd->scan_begin_arg, cmd->flags);
- if (cmd->scan_begin_arg < this_board->ai_ns_min)
- cmd->scan_begin_arg = this_board->ai_ns_min;
- if (tmp != cmd->scan_begin_arg)
- err++;
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) {
- tmp = cmd->convert_arg;
- i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,
+ arg = cmd->convert_arg;
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
&divisor1, &divisor2,
- &cmd->convert_arg, cmd->flags);
- if (cmd->convert_arg < this_board->ai_ns_min)
- cmd->convert_arg = this_board->ai_ns_min;
- if (tmp != cmd->convert_arg)
- err++;
- if (cmd->scan_begin_src == TRIG_TIMER
- && cmd->convert_src == TRIG_NOW) {
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
+
+ if (cmd->scan_begin_src == TRIG_TIMER &&
+ cmd->convert_src == TRIG_NOW) {
if (cmd->convert_arg == 0) {
- if (cmd->scan_begin_arg <
- this_board->ai_ns_min *
- (cmd->scan_end_arg + 2)) {
- cmd->scan_begin_arg =
- this_board->ai_ns_min *
- (cmd->scan_end_arg + 2);
- err++;
- }
+ arg = this_board->ai_ns_min *
+ (cmd->scan_end_arg + 2);
} else {
- if (cmd->scan_begin_arg <
- cmd->convert_arg * cmd->chanlist_len) {
- cmd->scan_begin_arg =
- cmd->convert_arg *
- cmd->chanlist_len;
- err++;
- }
+ arg = cmd->convert_arg * cmd->chanlist_len;
}
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ arg);
}
}
@@ -1329,23 +1275,23 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev,
return 0;
}
-static int Compute_and_setup_dma(struct comedi_device *dev)
+static int Compute_and_setup_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct pci9118_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned int dmalen0, dmalen1, i;
dmalen0 = devpriv->dmabuf_size[0];
dmalen1 = devpriv->dmabuf_size[1];
/* isn't output buff smaller that our DMA buff? */
- if (dmalen0 > (devpriv->ai_data_len)) {
- dmalen0 = devpriv->ai_data_len & ~3L; /*
- * align to 32bit down
- */
+ if (dmalen0 > s->async->prealloc_bufsz) {
+ /* align to 32bit down */
+ dmalen0 = s->async->prealloc_bufsz & ~3L;
}
- if (dmalen1 > (devpriv->ai_data_len)) {
- dmalen1 = devpriv->ai_data_len & ~3L; /*
- * align to 32bit down
- */
+ if (dmalen1 > s->async->prealloc_bufsz) {
+ /* align to 32bit down */
+ dmalen1 = s->async->prealloc_bufsz & ~3L;
}
/* we want wake up every scan? */
@@ -1359,8 +1305,6 @@ static int Compute_and_setup_dma(struct comedi_device *dev)
} else {
/* short first DMA buffer to one scan */
dmalen0 = devpriv->ai_n_realscanlen << 1;
- if (devpriv->useeoshandle)
- dmalen0 += 2;
if (dmalen0 < 4) {
dev_info(dev->class_dev,
"ERR: DMA0 buf len bug? (%d<4)\n",
@@ -1379,8 +1323,6 @@ static int Compute_and_setup_dma(struct comedi_device *dev)
} else {
/* short second DMA buffer to one scan */
dmalen1 = devpriv->ai_n_realscanlen << 1;
- if (devpriv->useeoshandle)
- dmalen1 -= 2;
if (dmalen1 < 4) {
dev_info(dev->class_dev,
"ERR: DMA1 buf len bug? (%d<4)\n",
@@ -1415,10 +1357,10 @@ static int Compute_and_setup_dma(struct comedi_device *dev)
/* fits whole measure into one DMA buffer? */
if (dmalen0 >
((devpriv->ai_n_realscanlen << 1) *
- devpriv->ai_scans)) {
+ cmd->stop_arg)) {
dmalen0 =
(devpriv->ai_n_realscanlen << 1) *
- devpriv->ai_scans;
+ cmd->stop_arg;
dmalen0 &= ~3L;
} else { /*
* fits whole measure into
@@ -1426,10 +1368,10 @@ static int Compute_and_setup_dma(struct comedi_device *dev)
*/
if (dmalen1 >
((devpriv->ai_n_realscanlen << 1) *
- devpriv->ai_scans - dmalen0))
+ cmd->stop_arg - dmalen0))
dmalen1 =
(devpriv->ai_n_realscanlen << 1) *
- devpriv->ai_scans - dmalen0;
+ cmd->stop_arg - dmalen0;
dmalen1 &= ~3L;
}
}
@@ -1441,18 +1383,18 @@ static int Compute_and_setup_dma(struct comedi_device *dev)
devpriv->dmabuf_use_size[1] = dmalen1;
#if 0
- if (devpriv->ai_n_scanlen < this_board->half_fifo_size) {
+ if (cmd->scan_end_arg < this_board->half_fifo_size) {
devpriv->dmabuf_panic_size[0] =
- (this_board->half_fifo_size / devpriv->ai_n_scanlen +
- 1) * devpriv->ai_n_scanlen * sizeof(short);
+ (this_board->half_fifo_size / cmd->scan_end_arg +
+ 1) * cmd->scan_end_arg * sizeof(short);
devpriv->dmabuf_panic_size[1] =
- (this_board->half_fifo_size / devpriv->ai_n_scanlen +
- 1) * devpriv->ai_n_scanlen * sizeof(short);
+ (this_board->half_fifo_size / cmd->scan_end_arg +
+ 1) * cmd->scan_end_arg * sizeof(short);
} else {
devpriv->dmabuf_panic_size[0] =
- (devpriv->ai_n_scanlen << 1) % devpriv->dmabuf_size[0];
+ (cmd->scan_end_arg << 1) % devpriv->dmabuf_size[0];
devpriv->dmabuf_panic_size[1] =
- (devpriv->ai_n_scanlen << 1) % devpriv->dmabuf_size[1];
+ (cmd->scan_end_arg << 1) % devpriv->dmabuf_size[1];
}
#endif
@@ -1499,9 +1441,6 @@ static int pci9118_ai_docmd_sampl(struct comedi_device *dev,
return -EIO;
}
- devpriv->int_ai_func = interrupt_pci9118_ai_onesample;
- /* transfer function */
-
if (devpriv->ai12_startstop)
pci9118_exttrg_add(dev, EXTTRG_AI);
/* activate EXT trigger */
@@ -1519,8 +1458,7 @@ static int pci9118_ai_docmd_sampl(struct comedi_device *dev,
outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
if (devpriv->ai_do != 3) {
- start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1,
- devpriv->ai_divisor2);
+ pci9118_start_pacer(dev, devpriv->ai_do);
devpriv->AdControlReg |= AdControl_SoftG;
}
outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
@@ -1533,8 +1471,9 @@ static int pci9118_ai_docmd_dma(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct pci9118_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
- Compute_and_setup_dma(dev);
+ Compute_and_setup_dma(dev, s);
switch (devpriv->ai_do) {
case 1:
@@ -1547,7 +1486,7 @@ static int pci9118_ai_docmd_dma(struct comedi_device *dev,
devpriv->AdFunctionReg =
AdFunction_PDTrg | AdFunction_PETrg | AdFunction_BM |
AdFunction_BS;
- if (devpriv->usessh && (!devpriv->softsshdelay))
+ if (cmd->convert_src == TRIG_NOW && !devpriv->softsshdelay)
devpriv->AdFunctionReg |= AdFunction_BSSH;
outl(devpriv->ai_n_realscanlen, dev->iobase + PCI9118_BURST);
break;
@@ -1579,9 +1518,6 @@ static int pci9118_ai_docmd_dma(struct comedi_device *dev,
/* activate EXT trigger */
}
- devpriv->int_ai_func = interrupt_pci9118_ai_dma;
- /* transfer function */
-
outl(0x02000000 | AINT_WRITE_COMPL,
devpriv->iobase_a + AMCC_OP_REG_INTCSR);
@@ -1589,8 +1525,7 @@ static int pci9118_ai_docmd_dma(struct comedi_device *dev,
outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
if (devpriv->ai_do != 3) {
- start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1,
- devpriv->ai_divisor2);
+ pci9118_start_pacer(dev, devpriv->ai_do);
devpriv->AdControlReg |= AdControl_SoftG;
}
outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
@@ -1609,12 +1544,6 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai12_startstop = 0;
devpriv->ai_flags = cmd->flags;
- devpriv->ai_n_chan = cmd->chanlist_len;
- devpriv->ai_n_scanlen = cmd->scan_end_arg;
- devpriv->ai_chanlist = cmd->chanlist;
- devpriv->ai_data_len = s->async->prealloc_bufsz;
- devpriv->ai_timer1 = 0;
- devpriv->ai_timer2 = 0;
devpriv->ai_add_front = 0;
devpriv->ai_add_back = 0;
devpriv->ai_maskerr = 0x10e;
@@ -1628,31 +1557,12 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
if (cmd->start_src == TRIG_INT) {
devpriv->ai12_startstop |= START_AI_INT;
- devpriv->ai_inttrig_start = cmd->start_arg;
s->async->inttrig = pci9118_ai_inttrig;
}
-#if 0
- if (cmd->stop_src == TRIG_INT) {
- devpriv->ai_neverending = 1;
- devpriv->ai12_startstop |= STOP_AI_INT;
- }
-#endif
if (cmd->stop_src == TRIG_NONE)
devpriv->ai_neverending = 1;
- if (cmd->stop_src == TRIG_COUNT) {
- devpriv->ai_scans = cmd->stop_arg;
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->ai_neverending = 0;
- } else {
- devpriv->ai_scans = 0;
- }
-
- /* use sample&hold signal? */
- if (cmd->convert_src == TRIG_NOW)
- devpriv->usessh = 1;
- /* yes */
- else
- devpriv->usessh = 0;
- /* no */
/*
* use additional sample at end of every scan
@@ -1660,11 +1570,10 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
*/
devpriv->ai_add_front = 0;
devpriv->ai_add_back = 0;
- devpriv->useeoshandle = 0;
if (devpriv->master) {
devpriv->usedma = 1;
if ((cmd->flags & TRIG_WAKE_EOS) &&
- (devpriv->ai_n_scanlen == 1)) {
+ (cmd->scan_end_arg == 1)) {
if (cmd->convert_src == TRIG_NOW)
devpriv->ai_add_back = 1;
if (cmd->convert_src == TRIG_TIMER) {
@@ -1676,13 +1585,9 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
}
if ((cmd->flags & TRIG_WAKE_EOS) &&
- (devpriv->ai_n_scanlen & 1) &&
- (devpriv->ai_n_scanlen > 1)) {
+ (cmd->scan_end_arg & 1) &&
+ (cmd->scan_end_arg > 1)) {
if (cmd->scan_begin_src == TRIG_FOLLOW) {
- /*
- * vpriv->useeoshandle=1; // change DMA transfer
- * block to fit EOS on every second call
- */
devpriv->usedma = 0;
/*
* XXX maybe can be corrected to use 16 bit DMA
@@ -1702,7 +1607,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* we need software S&H signal?
* It adds two samples before every scan as minimum
*/
- if (devpriv->usessh && devpriv->softsshdelay) {
+ if (cmd->convert_src == TRIG_NOW && devpriv->softsshdelay) {
devpriv->ai_add_front = 2;
if ((devpriv->usedma == 1) && (devpriv->ai_add_back == 1)) {
/* move it to front */
@@ -1719,7 +1624,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_add_front = addchans + 1;
if (devpriv->usedma == 1)
if ((devpriv->ai_add_front +
- devpriv->ai_n_chan +
+ cmd->chanlist_len +
devpriv->ai_add_back) & 1)
devpriv->ai_add_front++;
/* round up to 32 bit */
@@ -1728,21 +1633,20 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* well, we now know what must be all added */
devpriv->ai_n_realscanlen = /*
* what we must take from card in real
- * to have ai_n_scanlen on output?
+ * to have cmd->scan_end_arg on output?
*/
- (devpriv->ai_add_front + devpriv->ai_n_chan +
- devpriv->ai_add_back) * (devpriv->ai_n_scanlen /
- devpriv->ai_n_chan);
+ (devpriv->ai_add_front + cmd->chanlist_len +
+ devpriv->ai_add_back) * (cmd->scan_end_arg /
+ cmd->chanlist_len);
/* check and setup channel list */
- if (!check_channel_list(dev, s, devpriv->ai_n_chan,
- devpriv->ai_chanlist, devpriv->ai_add_front,
+ if (!check_channel_list(dev, s, cmd->chanlist_len,
+ cmd->chanlist, devpriv->ai_add_front,
devpriv->ai_add_back))
return -EINVAL;
- if (!setup_channel_list(dev, s, devpriv->ai_n_chan,
- devpriv->ai_chanlist, 0, devpriv->ai_add_front,
- devpriv->ai_add_back, devpriv->usedma,
- devpriv->useeoshandle))
+ if (!setup_channel_list(dev, s, cmd->chanlist_len,
+ cmd->chanlist, 0, devpriv->ai_add_front,
+ devpriv->ai_add_back, devpriv->usedma))
return -EINVAL;
/* compute timers settings */
@@ -1764,9 +1668,8 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_flags,
devpriv->ai_n_realscanlen,
&devpriv->ai_divisor1,
- &devpriv->ai_divisor2, devpriv->usessh,
+ &devpriv->ai_divisor2,
devpriv->ai_add_front);
- devpriv->ai_timer2 = cmd->convert_arg;
}
if ((cmd->scan_begin_src == TRIG_TIMER) &&
@@ -1786,10 +1689,8 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_flags,
devpriv->ai_n_realscanlen,
&devpriv->ai_divisor1,
- &devpriv->ai_divisor2, devpriv->usessh,
+ &devpriv->ai_divisor2,
devpriv->ai_add_front);
- devpriv->ai_timer1 = cmd->scan_begin_arg;
- devpriv->ai_timer2 = cmd->convert_arg;
}
if ((cmd->scan_begin_src == TRIG_FOLLOW)
@@ -1797,7 +1698,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_do = 3;
}
- start_pacer(dev, -1, 0, 0); /* stop pacer */
+ pci9118_start_pacer(dev, -1); /* stop pacer */
devpriv->AdControlReg = 0; /*
* bipolar, S.E., use 8254, stop 8354,
@@ -1823,7 +1724,6 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_act_scan = 0;
devpriv->ai_act_dmapos = 0;
s->async->cur_chan = 0;
- devpriv->ai_buf_ptr = 0;
if (devpriv->usedma)
ret = pci9118_ai_docmd_dma(dev, s);
@@ -1844,7 +1744,7 @@ static int pci9118_reset(struct comedi_device *dev)
/* disable interrupts source */
outl(0x30, dev->iobase + PCI9118_CNTCTRL);
/* outl(0xb4, dev->iobase + PCI9118_CNTCTRL); */
- start_pacer(dev, 0, 0, 0); /* stop 8254 counters */
+ pci9118_start_pacer(dev, 0); /* stop 8254 counters */
devpriv->AdControlReg = 0;
outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
/*
@@ -1887,7 +1787,6 @@ static int pci9118_reset(struct comedi_device *dev)
* disable INT and DMA
*/
- devpriv->cnt0_users = 0;
devpriv->exttrg_users = 0;
return 0;
@@ -1934,28 +1833,6 @@ static struct pci_dev *pci9118_find_pci(struct comedi_device *dev,
return NULL;
}
-static void pci9118_report_attach(struct comedi_device *dev, unsigned int irq)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- struct pci9118_private *devpriv = dev->private;
- char irqbuf[30];
- char muxbuf[30];
-
- if (irq)
- snprintf(irqbuf, sizeof(irqbuf), "irq %u%s", irq,
- (dev->irq ? "" : " UNAVAILABLE"));
- else
- snprintf(irqbuf, sizeof(irqbuf), "irq DISABLED");
- if (devpriv->usemux)
- snprintf(muxbuf, sizeof(muxbuf), "ext mux %u chans",
- devpriv->usemux);
- else
- snprintf(muxbuf, sizeof(muxbuf), "no ext mux");
- dev_info(dev->class_dev, "%s (pci %s, %s, %sbus master, %s) attached\n",
- dev->board_name, pci_name(pcidev), irqbuf,
- (devpriv->master ? "" : "no "), muxbuf);
-}
-
static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
int master, int ext_mux, int softsshdelay,
int hw_err_mask)
@@ -1965,7 +1842,6 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct comedi_subdevice *s;
int ret, pages, i;
- unsigned int irq;
u16 u16w;
dev->board_name = this_board->name;
@@ -1993,8 +1869,6 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
if (devpriv->dmabuf_virt[i]) {
devpriv->dmabuf_pages[i] = pages;
devpriv->dmabuf_size[i] = PAGE_SIZE * pages;
- devpriv->dmabuf_samples[i] =
- devpriv->dmabuf_size[i] >> 1;
devpriv->dmabuf_hw[i] =
virt_to_bus((void *)
devpriv->dmabuf_virt[i]);
@@ -2036,12 +1910,18 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
pci_write_config_word(pcidev, PCI_COMMAND, u16w | 64);
/* Enable parity check for parity error */
+ if (!disable_irq && pcidev->irq) {
+ ret = request_irq(pcidev->irq, pci9118_interrupt, IRQF_SHARED,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = pcidev->irq;
+ }
+
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
return ret;
s = &dev->subdevices[0];
- dev->read_subdev = s;
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
if (devpriv->usemux)
@@ -2050,11 +1930,17 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
s->n_chan = this_board->n_aichan;
s->maxdata = this_board->ai_maxdata;
- s->len_chanlist = this_board->n_aichanlist;
s->range_table = this_board->rangelist_ai;
- s->cancel = pci9118_ai_cancel;
s->insn_read = pci9118_insn_read_ai;
- s->munge = pci9118_ai_munge;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = this_board->n_aichanlist;
+ s->do_cmdtest = pci9118_ai_cmdtest;
+ s->do_cmd = pci9118_ai_cmd;
+ s->cancel = pci9118_ai_cancel;
+ s->munge = pci9118_ai_munge;
+ }
s = &dev->subdevices[1];
s->type = COMEDI_SUBD_AO;
@@ -2084,43 +1970,11 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
s->range_table = &range_digital;
s->insn_bits = pci9118_insn_bits_do;
- devpriv->valid = 1;
- devpriv->i8254_osc_base = I8254_OSC_BASE_4MHZ;
devpriv->ai_maskharderr = 0x10a;
/* default measure crash condition */
if (hw_err_mask) /* disable some requested */
devpriv->ai_maskharderr &= ~hw_err_mask;
- switch (this_board->ai_maxdata) {
- case 0xffff:
- devpriv->ai16bits = 1;
- break;
- default:
- devpriv->ai16bits = 0;
- break;
- }
-
- if (disable_irq)
- irq = 0;
- else
- irq = pcidev->irq;
- if (irq > 0) {
- if (request_irq(irq, interrupt_pci9118, IRQF_SHARED,
- dev->board_name, dev)) {
- dev_warn(dev->class_dev,
- "unable to allocate IRQ %u, DISABLING IT\n",
- irq);
- } else {
- dev->irq = irq;
- /* Enable AI commands */
- s = &dev->subdevices[0];
- s->subdev_flags |= SDF_CMD_READ;
- s->do_cmdtest = pci9118_ai_cmdtest;
- s->do_cmd = pci9118_ai_cmd;
- }
- }
-
- pci9118_report_attach(dev, irq);
return 0;
}
@@ -2183,7 +2037,7 @@ static void pci9118_detach(struct comedi_device *dev)
struct pci9118_private *devpriv = dev->private;
if (devpriv) {
- if (devpriv->valid)
+ if (dev->iobase)
pci9118_reset(dev);
if (dev->irq)
free_irq(dev->irq, dev);
@@ -2217,7 +2071,7 @@ static int adl_pci9118_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(adl_pci9118_pci_table) = {
+static const struct pci_device_id adl_pci9118_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c
index 8150a67cd1f..b4ea37704ea 100644
--- a/drivers/staging/comedi/drivers/adq12b.c
+++ b/drivers/staging/comedi/drivers/adq12b.c
@@ -94,24 +94,23 @@ If you do not specify any options, they will default to
/* mask of the bit at STINR to check end of conversion */
#define ADQ12B_EOC 0x20
-#define TIMEOUT 20
-
/* available ranges through the PGA gains */
-static const struct comedi_lrange range_adq12b_ai_bipolar = { 4, {
- BIP_RANGE(5),
- BIP_RANGE(2),
- BIP_RANGE(1),
- BIP_RANGE(0.5)
- }
+static const struct comedi_lrange range_adq12b_ai_bipolar = {
+ 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(2),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5)
+ }
};
-static const struct comedi_lrange range_adq12b_ai_unipolar = { 4, {
- UNI_RANGE(5),
- UNI_RANGE(2),
- UNI_RANGE(1),
- UNI_RANGE
- (0.5)
- }
+static const struct comedi_lrange range_adq12b_ai_unipolar = {
+ 4, {
+ UNI_RANGE(5),
+ UNI_RANGE(2),
+ UNI_RANGE(1),
+ UNI_RANGE(0.5)
+ }
};
struct adq12b_private {
@@ -121,19 +120,28 @@ struct adq12b_private {
int last_range;
};
-/*
- * "instructions" read/write data in "one-shot" or "software-triggered"
- * mode.
- */
+static int adq12b_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned char status;
+
+ status = inb(dev->iobase + ADQ12B_STINR);
+ if (status & ADQ12B_EOC)
+ return 0;
+ return -EBUSY;
+}
static int adq12b_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
struct adq12b_private *devpriv = dev->private;
- int n, i;
+ int n;
int range, channel;
unsigned char hi, lo, status;
+ int ret;
/* change channel and range only if it is different from the previous */
range = CR_RANGE(insn->chanspec);
@@ -150,20 +158,14 @@ static int adq12b_ai_rinsn(struct comedi_device *dev,
for (n = 0; n < insn->n; n++) {
/* wait for end of conversion */
- i = 0;
- do {
- /* udelay(1); */
- status = inb(dev->iobase + ADQ12B_STINR);
- status = status & ADQ12B_EOC;
- } while (status == 0 && ++i < TIMEOUT);
- /* } while (++i < 10); */
+ ret = comedi_timeout(dev, s, insn, adq12b_ai_eoc, 0);
+ if (ret)
+ return ret;
/* read data */
hi = inb(dev->iobase + ADQ12B_ADHIG);
lo = inb(dev->iobase + ADQ12B_ADLOW);
- /* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n",
- channel, range, status, hi, lo); */
data[n] = (hi << 8) | lo;
}
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index c3fdcabe9ae..602b7a1e40e 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -51,10 +51,6 @@ Configuration options:
#include "8253.h"
#include "amcc_s5933.h"
-#define PCI171x_PARANOIDCHECK /* if defined, then is used code which control
- * correct channel number on every 12 bit
- * sample */
-
/* hardware types of the cards */
#define TYPE_PCI171X 0
#define TYPE_PCI1713 2
@@ -73,6 +69,9 @@ Configuration options:
#define PCI171x_DAREF 14 /* W: D/A reference control */
#define PCI171x_DI 16 /* R: digi inputs */
#define PCI171x_DO 16 /* R: digi inputs */
+
+#define PCI171X_TIMER_BASE 0x18
+
#define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
#define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
#define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
@@ -115,65 +114,70 @@ Configuration options:
/* D/A synchronized control (PCI1720_SYNCONT) */
#define Syncont_SC0 1 /* set synchronous output mode */
-static const struct comedi_lrange range_pci1710_3 = { 9, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- BIP_RANGE(10),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25)
- }
+static const struct comedi_lrange range_pci1710_3 = {
+ 9, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ BIP_RANGE(10),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
0x10, 0x11, 0x12, 0x13 };
-static const struct comedi_lrange range_pci1710hg = { 12, {
- BIP_RANGE(5),
- BIP_RANGE(0.5),
- BIP_RANGE(0.05),
- BIP_RANGE(0.005),
- BIP_RANGE(10),
- BIP_RANGE(1),
- BIP_RANGE(0.1),
- BIP_RANGE(0.01),
- UNI_RANGE(10),
- UNI_RANGE(1),
- UNI_RANGE(0.1),
- UNI_RANGE(0.01)
- }
+static const struct comedi_lrange range_pci1710hg = {
+ 12, {
+ BIP_RANGE(5),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.05),
+ BIP_RANGE(0.005),
+ BIP_RANGE(10),
+ BIP_RANGE(1),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.01),
+ UNI_RANGE(10),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1),
+ UNI_RANGE(0.01)
+ }
};
static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x10, 0x11,
0x12, 0x13 };
-static const struct comedi_lrange range_pci17x1 = { 5, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625)
- }
+static const struct comedi_lrange range_pci17x1 = {
+ 5, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625)
+ }
};
static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
-static const struct comedi_lrange range_pci1720 = { 4, {
- UNI_RANGE(5),
- UNI_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(10)
- }
+static const struct comedi_lrange range_pci1720 = {
+ 4, {
+ UNI_RANGE(5),
+ UNI_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(10)
+ }
};
-static const struct comedi_lrange range_pci171x_da = { 2, {
- UNI_RANGE(5),
- UNI_RANGE(10),
- }
+static const struct comedi_lrange range_pci171x_da = {
+ 2, {
+ UNI_RANGE(5),
+ UNI_RANGE(10)
+ }
};
enum pci1710_boardid {
@@ -293,29 +297,18 @@ static const struct boardtype boardtypes[] = {
};
struct pci1710_private {
- char neverending_ai; /* we do unlimited AI */
unsigned int CntrlReg; /* Control register */
- unsigned int i8254_osc_base; /* frequence of onboard oscilator */
- unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */
unsigned int ai_act_scan; /* how many scans we finished */
- unsigned int ai_act_chan; /* actual position in actual scan */
- unsigned int ai_buf_ptr; /* data buffer ptr in samples */
- unsigned char ai_eos; /* 1=EOS wake up */
unsigned char ai_et;
unsigned int ai_et_CntrlReg;
unsigned int ai_et_MuxVal;
- unsigned int ai_et_div1, ai_et_div2;
+ unsigned int next_divisor1;
+ unsigned int next_divisor2;
+ unsigned int divisor1;
+ unsigned int divisor2;
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 char saved_seglen; /* len of the non-repeating chanlist */
unsigned char da_ranges; /* copy of D/A outpit range register */
- unsigned int ai_scans; /* len of scanlist */
- unsigned int ai_n_chan; /* how many channels is measured */
- unsigned int *ai_chanlist; /* actaul chanlist */
- unsigned int ai_flags; /* flaglist */
- unsigned int ai_data_len; /* len of data buffer */
- unsigned int ai_timer1; /* timers */
- unsigned int ai_timer2;
unsigned short ao_data[4]; /* data output buffer */
unsigned int cnt0_write_wait; /* after a write, wait for update of the
* internal state */
@@ -329,62 +322,90 @@ static const unsigned int muxonechan[] = {
0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
};
-/*
-==============================================================================
- Check if channel list from user is built correctly
- If it's ok, then program scan/gain logic.
- This works for all cards.
-*/
-static int check_channel_list(struct comedi_device *dev,
+static int pci171x_ai_dropout(struct comedi_device *dev,
struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan)
+ unsigned int chan,
+ unsigned int val)
{
+ const struct boardtype *board = comedi_board(dev);
+ struct pci1710_private *devpriv = dev->private;
+
+ if (board->cardtype != TYPE_PCI1713) {
+ if ((val & 0xf000) != devpriv->act_chanlist[chan]) {
+ dev_err(dev->class_dev,
+ "A/D data droput: received from channel %d, expected %d\n",
+ (val >> 12) & 0xf,
+ (devpriv->act_chanlist[chan] >> 12) & 0xf);
+ return -ENODATA;
+ }
+ }
+ return 0;
+}
+
+static int pci171x_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ struct pci1710_private *devpriv = dev->private;
+ unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
+ unsigned int last_aref = CR_AREF(cmd->chanlist[0]);
+ unsigned int next_chan = (chan0 + 1) % s->n_chan;
unsigned int chansegment[32];
- unsigned int i, nowmustbechan, seglen, segpos;
+ unsigned int seglen;
+ int i;
- /* correct channel and range number check itself comedi/range.c */
- if (n_chan < 1) {
- comedi_error(dev, "range/channel list is empty!");
+ if (cmd->chanlist_len == 1) {
+ devpriv->saved_seglen = cmd->chanlist_len;
return 0;
}
- if (n_chan == 1)
- return 1; /* seglen=1 */
+ /* first channel is always ok */
+ chansegment[0] = cmd->chanlist[0];
+
+ for (i = 1; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+ unsigned int aref = CR_AREF(cmd->chanlist[i]);
- chansegment[0] = chanlist[0]; /* first channel is every time ok */
- for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
- if (chanlist[0] == chanlist[i])
+ if (cmd->chanlist[0] == cmd->chanlist[i])
break; /* we detected a loop, stop */
- if ((CR_CHAN(chanlist[i]) & 1) &&
- (CR_AREF(chanlist[i]) == AREF_DIFF)) {
- comedi_error(dev, "Odd channel cannot be differential input!\n");
- return 0;
+
+ if (aref == AREF_DIFF && (chan & 1)) {
+ dev_err(dev->class_dev,
+ "Odd channel cannot be differential input!\n");
+ return -EINVAL;
}
- nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
- if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
- nowmustbechan = (nowmustbechan + 1) % s->n_chan;
- if (nowmustbechan != CR_CHAN(chanlist[i])) {
- printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
- i, CR_CHAN(chanlist[i]), nowmustbechan,
- CR_CHAN(chanlist[0]));
- return 0;
+
+ if (last_aref == AREF_DIFF)
+ next_chan = (next_chan + 1) % s->n_chan;
+ if (chan != next_chan) {
+ dev_err(dev->class_dev,
+ "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
+ i, chan, next_chan, chan0);
+ return -EINVAL;
}
- chansegment[i] = chanlist[i]; /* next correct channel in list */
- }
- for (i = 0, segpos = 0; i < n_chan; i++) {
- if (chanlist[i] != chansegment[i % seglen]) {
- printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
- i, CR_CHAN(chansegment[i]),
- CR_RANGE(chansegment[i]),
- CR_AREF(chansegment[i]),
- CR_CHAN(chanlist[i % seglen]),
- CR_RANGE(chanlist[i % seglen]),
- CR_AREF(chansegment[i % seglen]));
- return 0;
+ /* next correct channel in list */
+ chansegment[i] = cmd->chanlist[i];
+ last_aref = aref;
+ }
+ seglen = i;
+
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ if (cmd->chanlist[i] != chansegment[i % seglen]) {
+ dev_err(dev->class_dev,
+ "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
+ i, CR_CHAN(chansegment[i]),
+ CR_RANGE(chansegment[i]),
+ CR_AREF(chansegment[i]),
+ CR_CHAN(cmd->chanlist[i % seglen]),
+ CR_RANGE(cmd->chanlist[i % seglen]),
+ CR_AREF(chansegment[i % seglen]));
+ return -EINVAL;
}
}
- return seglen;
+ devpriv->saved_seglen = seglen;
+
+ return 0;
}
static void setup_channel_list(struct comedi_device *dev,
@@ -396,9 +417,6 @@ static void setup_channel_list(struct comedi_device *dev,
struct pci1710_private *devpriv = dev->private;
unsigned int i, range, chanprog;
- devpriv->act_chanlist_len = seglen;
- devpriv->act_chanlist_pos = 0;
-
for (i = 0; i < seglen; i++) { /* store range list to card */
chanprog = muxonechan[CR_CHAN(chanlist[i])];
outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
@@ -406,17 +424,13 @@ static void setup_channel_list(struct comedi_device *dev,
if (CR_AREF(chanlist[i]) == AREF_DIFF)
range |= 0x0020;
outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
-#ifdef PCI171x_PARANOIDCHECK
devpriv->act_chanlist[i] =
(CR_CHAN(chanlist[i]) << 12) & 0xf000;
-#endif
}
-#ifdef PCI171x_PARANOIDCHECK
for ( ; i < n_chan; i++) { /* store remainder of channel list */
devpriv->act_chanlist[i] =
(CR_CHAN(chanlist[i]) << 12) & 0xf000;
}
-#endif
devpriv->ai_et_MuxVal =
CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
@@ -424,19 +438,27 @@ static void setup_channel_list(struct comedi_device *dev,
outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
}
-/*
-==============================================================================
-*/
+static int pci171x_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + PCI171x_STATUS);
+ if ((status & Status_FE) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int pci171x_insn_read_ai(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct pci1710_private *devpriv = dev->private;
- int n, timeout;
-#ifdef PCI171x_PARANOIDCHECK
- const struct boardtype *this_board = comedi_board(dev);
- unsigned int idata;
-#endif
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int ret = 0;
+ int i;
devpriv->CntrlReg &= Control_CNT0;
devpriv->CntrlReg |= Control_SW; /* set software trigger */
@@ -446,39 +468,27 @@ static int pci171x_insn_read_ai(struct comedi_device *dev,
setup_channel_list(dev, s, &insn->chanspec, 1, 1);
- for (n = 0; n < insn->n; n++) {
+ for (i = 0; i < insn->n; i++) {
+ unsigned int val;
+
outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
- /* udelay(1); */
- timeout = 100;
- while (timeout--) {
- if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE))
- goto conv_finish;
- }
- comedi_error(dev, "A/D insn timeout");
- outb(0, dev->iobase + PCI171x_CLRFIFO);
- outb(0, dev->iobase + PCI171x_CLRINT);
- data[n] = 0;
- return -ETIME;
-
-conv_finish:
-#ifdef PCI171x_PARANOIDCHECK
- idata = inw(dev->iobase + PCI171x_AD_DATA);
- if (this_board->cardtype != TYPE_PCI1713)
- if ((idata & 0xf000) != devpriv->act_chanlist[0]) {
- comedi_error(dev, "A/D insn data droput!");
- return -ETIME;
- }
- data[n] = idata & 0x0fff;
-#else
- data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff;
-#endif
+ ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
+ if (ret)
+ break;
+
+ val = inw(dev->iobase + PCI171x_AD_DATA);
+ ret = pci171x_ai_dropout(dev, s, chan, val);
+ if (ret)
+ break;
+
+ data[i] = val & s->maxdata;
}
outb(0, dev->iobase + PCI171x_CLRFIFO);
outb(0, dev->iobase + PCI171x_CLRINT);
- return n;
+ return ret ? ret : insn->n;
}
/*
@@ -489,6 +499,7 @@ static int pci171x_insn_write_ao(struct comedi_device *dev,
struct comedi_insn *insn, unsigned int *data)
{
struct pci1710_private *devpriv = dev->private;
+ unsigned int val;
int n, chan, range, ofs;
chan = CR_CHAN(insn->chanspec);
@@ -504,11 +515,14 @@ static int pci171x_insn_write_ao(struct comedi_device *dev,
outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
ofs = PCI171x_DA1;
}
+ val = devpriv->ao_data[chan];
- for (n = 0; n < insn->n; n++)
- outw(data[n], dev->iobase + ofs);
+ for (n = 0; n < insn->n; n++) {
+ val = data[n];
+ outw(val, dev->iobase + ofs);
+ }
- devpriv->ao_data[chan] = data[n];
+ devpriv->ao_data[chan] = val;
return n;
@@ -556,20 +570,18 @@ static int pci171x_insn_bits_do(struct comedi_device *dev,
return insn->n;
}
-/*
-==============================================================================
-*/
-static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2)
+static void pci171x_start_pacer(struct comedi_device *dev,
+ bool load_counters)
{
- outw(0xb4, dev->iobase + PCI171x_CNTCTRL);
- outw(0x74, dev->iobase + PCI171x_CNTCTRL);
-
- if (mode == 1) {
- outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2);
- outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2);
- outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1);
- outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1);
+ struct pci1710_private *devpriv = dev->private;
+ unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
+
+ i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
+
+ if (load_counters) {
+ i8254_write(timer_base, 1, 2, devpriv->divisor2);
+ i8254_write(timer_base, 1, 1, devpriv->divisor1);
}
}
@@ -674,6 +686,7 @@ static int pci1720_insn_write_ao(struct comedi_device *dev,
struct comedi_insn *insn, unsigned int *data)
{
struct pci1710_private *devpriv = dev->private;
+ unsigned int val;
int n, rangereg, chan;
chan = CR_CHAN(insn->chanspec);
@@ -683,13 +696,15 @@ static int pci1720_insn_write_ao(struct comedi_device *dev,
outb(rangereg, dev->iobase + PCI1720_RANGE);
devpriv->da_ranges = rangereg;
}
+ val = devpriv->ao_data[chan];
for (n = 0; n < insn->n; n++) {
- outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
+ val = data[n];
+ outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
}
- devpriv->ao_data[chan] = data[n];
+ devpriv->ao_data[chan] = val;
return n;
}
@@ -709,101 +724,73 @@ static int pci171x_ai_cancel(struct comedi_device *dev,
devpriv->CntrlReg |= Control_SW;
outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
- start_pacer(dev, -1, 0, 0);
+ pci171x_start_pacer(dev, false);
outb(0, dev->iobase + PCI171x_CLRFIFO);
outb(0, dev->iobase + PCI171x_CLRINT);
break;
}
- devpriv->ai_do = 0;
devpriv->ai_act_scan = 0;
s->async->cur_chan = 0;
- devpriv->ai_buf_ptr = 0;
- devpriv->neverending_ai = 0;
return 0;
}
-/*
-==============================================================================
-*/
-static void interrupt_pci1710_every_sample(void *d)
+static void pci1710_handle_every_sample(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- struct comedi_device *dev = d;
struct pci1710_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
- int m;
-#ifdef PCI171x_PARANOIDCHECK
- const struct boardtype *this_board = comedi_board(dev);
- unsigned short sampl;
-#endif
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int status;
+ unsigned int val;
+ int ret;
- m = inw(dev->iobase + PCI171x_STATUS);
- if (m & Status_FE) {
- printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m);
- pci171x_ai_cancel(dev, s);
+ status = inw(dev->iobase + PCI171x_STATUS);
+ if (status & Status_FE) {
+ dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
- if (m & Status_FF) {
- printk
- ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
- dev->minor, m);
- pci171x_ai_cancel(dev, s);
+ if (status & Status_FF) {
+ dev_dbg(dev->class_dev,
+ "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
-#ifdef PCI171x_PARANOIDCHECK
- sampl = inw(dev->iobase + PCI171x_AD_DATA);
- if (this_board->cardtype != TYPE_PCI1713)
- if ((sampl & 0xf000) !=
- devpriv->act_chanlist[s->async->cur_chan]) {
- printk
- ("comedi: A/D data dropout: received data from channel %d, expected %d!\n",
- (sampl & 0xf000) >> 12,
- (devpriv->
- act_chanlist[s->
- async->cur_chan] & 0xf000) >>
- 12);
- pci171x_ai_cancel(dev, s);
- s->async->events |=
- COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return;
- }
- comedi_buf_put(s->async, sampl & 0x0fff);
-#else
- comedi_buf_put(s->async,
- inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
-#endif
- ++s->async->cur_chan;
+ val = inw(dev->iobase + PCI171x_AD_DATA);
+ ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
+ if (ret) {
+ s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ break;
+ }
- if (s->async->cur_chan >= devpriv->ai_n_chan)
+ comedi_buf_put(s, val & s->maxdata);
+
+ s->async->cur_chan++;
+ if (s->async->cur_chan >= cmd->chanlist_len)
s->async->cur_chan = 0;
if (s->async->cur_chan == 0) { /* one scan done */
devpriv->ai_act_scan++;
- if ((!devpriv->neverending_ai) &&
- (devpriv->ai_act_scan >= devpriv->ai_scans)) {
+ if (cmd->stop_src == TRIG_COUNT &&
+ devpriv->ai_act_scan >= cmd->stop_arg) {
/* all data sampled */
- pci171x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
- return;
+ break;
}
}
}
outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
/*
@@ -813,78 +800,57 @@ static int move_block_from_fifo(struct comedi_device *dev,
struct comedi_subdevice *s, int n, int turn)
{
struct pci1710_private *devpriv = dev->private;
- int i, j;
-#ifdef PCI171x_PARANOIDCHECK
- const struct boardtype *this_board = comedi_board(dev);
- unsigned short sampl;
-#endif
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int val;
+ int ret;
+ int i;
- j = s->async->cur_chan;
for (i = 0; i < n; i++) {
-#ifdef PCI171x_PARANOIDCHECK
- sampl = inw(dev->iobase + PCI171x_AD_DATA);
- if (this_board->cardtype != TYPE_PCI1713)
- if ((sampl & 0xf000) != devpriv->act_chanlist[j]) {
- printk
- ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
- dev->minor, (sampl & 0xf000) >> 12,
- (devpriv->act_chanlist[j] & 0xf000) >> 12,
- i, j, devpriv->ai_act_scan, n, turn,
- sampl);
- pci171x_ai_cancel(dev, s);
- s->async->events |=
- COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return 1;
- }
- comedi_buf_put(s->async, sampl & 0x0fff);
-#else
- comedi_buf_put(s->async,
- inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff);
-#endif
- j++;
- if (j >= devpriv->ai_n_chan) {
- j = 0;
+ val = inw(dev->iobase + PCI171x_AD_DATA);
+
+ ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
+ if (ret) {
+ s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ return ret;
+ }
+
+ comedi_buf_put(s, val & s->maxdata);
+
+ s->async->cur_chan++;
+ if (s->async->cur_chan >= cmd->chanlist_len) {
+ s->async->cur_chan = 0;
devpriv->ai_act_scan++;
}
}
- s->async->cur_chan = j;
return 0;
}
-/*
-==============================================================================
-*/
-static void interrupt_pci1710_half_fifo(void *d)
+static void pci1710_handle_fifo(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- struct comedi_device *dev = d;
const struct boardtype *this_board = comedi_board(dev);
struct pci1710_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
+ struct comedi_cmd *cmd = &s->async->cmd;
int m, samplesinbuf;
m = inw(dev->iobase + PCI171x_STATUS);
if (!(m & Status_FH)) {
- printk("comedi%d: A/D FIFO not half full! (%4x)\n",
- dev->minor, m);
- pci171x_ai_cancel(dev, s);
+ dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
if (m & Status_FF) {
- printk
- ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n",
- dev->minor, m);
- pci171x_ai_cancel(dev, s);
+ dev_dbg(dev->class_dev,
+ "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
samplesinbuf = this_board->fifo_half_size;
- if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) {
- m = devpriv->ai_data_len / sizeof(short);
+ if (samplesinbuf * sizeof(short) >= s->async->prealloc_bufsz) {
+ m = s->async->prealloc_bufsz / sizeof(short);
if (move_block_from_fifo(dev, s, m, 0))
return;
samplesinbuf -= m;
@@ -895,17 +861,16 @@ static void interrupt_pci1710_half_fifo(void *d)
return;
}
- if (!devpriv->neverending_ai)
- if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data
- sampled */
- pci171x_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
- return;
- }
+ if (cmd->stop_src == TRIG_COUNT &&
+ devpriv->ai_act_scan >= cmd->stop_arg) {
+ /* all data sampled */
+ s->async->events |= COMEDI_CB_EOA;
+ cfc_handle_events(dev, s);
+ return;
+ }
outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
/*
@@ -915,9 +880,15 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d)
{
struct comedi_device *dev = d;
struct pci1710_private *devpriv = dev->private;
+ struct comedi_subdevice *s;
+ struct comedi_cmd *cmd;
if (!dev->attached) /* is device attached? */
return IRQ_NONE; /* no, exit */
+
+ s = dev->read_subdev;
+ cmd = &s->async->cmd;
+
/* is this interrupt from our board? */
if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
return IRQ_NONE; /* no, exit */
@@ -932,95 +903,59 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d)
outb(0, dev->iobase + PCI171x_CLRINT);
outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
- /* start pacer */
- start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2);
+ pci171x_start_pacer(dev, true);
return IRQ_HANDLED;
}
- if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */
- interrupt_pci1710_every_sample(d);
- } else {
- interrupt_pci1710_half_fifo(d);
- }
+
+ if (cmd->flags & TRIG_WAKE_EOS)
+ pci1710_handle_every_sample(dev, s);
+ else
+ pci1710_handle_fifo(dev, s);
+
return IRQ_HANDLED;
}
-/*
-==============================================================================
-*/
-static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
- const struct boardtype *this_board = comedi_board(dev);
struct pci1710_private *devpriv = dev->private;
- unsigned int divisor1 = 0, divisor2 = 0;
- unsigned int seglen;
+ struct comedi_cmd *cmd = &s->async->cmd;
- start_pacer(dev, -1, 0, 0); /* stop pacer */
+ pci171x_start_pacer(dev, false);
- seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
- devpriv->ai_n_chan);
- if (seglen < 1)
- return -EINVAL;
- setup_channel_list(dev, s, devpriv->ai_chanlist,
- devpriv->ai_n_chan, seglen);
+ setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len,
+ devpriv->saved_seglen);
outb(0, dev->iobase + PCI171x_CLRFIFO);
outb(0, dev->iobase + PCI171x_CLRINT);
- devpriv->ai_do = mode;
-
devpriv->ai_act_scan = 0;
s->async->cur_chan = 0;
- devpriv->ai_buf_ptr = 0;
- devpriv->neverending_ai = 0;
devpriv->CntrlReg &= Control_CNT0;
- /* don't we want wake up every scan? devpriv->ai_eos=1; */
- if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
- devpriv->ai_eos = 1;
- } else {
+ if ((cmd->flags & TRIG_WAKE_EOS) == 0)
devpriv->CntrlReg |= Control_ONEFH;
- devpriv->ai_eos = 0;
- }
- if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
- devpriv->neverending_ai = 1;
- /* well, user want neverending */
- else
- devpriv->neverending_ai = 0;
+ devpriv->divisor1 = devpriv->next_divisor1;
+ devpriv->divisor2 = devpriv->next_divisor2;
- switch (mode) {
- case 1:
- case 2:
- if (devpriv->ai_timer1 < this_board->ai_ns_min)
- devpriv->ai_timer1 = this_board->ai_ns_min;
+ if (cmd->convert_src == TRIG_TIMER) {
devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
- if (mode == 2) {
+ if (cmd->start_src == TRIG_EXT) {
devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
devpriv->CntrlReg &=
~(Control_PACER | Control_ONEFH | Control_GATE);
devpriv->CntrlReg |= Control_EXT;
devpriv->ai_et = 1;
- } else {
+ } else { /* TRIG_NOW */
devpriv->ai_et = 0;
}
- i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,
- &divisor1, &divisor2,
- &devpriv->ai_timer1,
- devpriv->ai_flags);
outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
- if (mode != 2) {
- /* start pacer */
- start_pacer(dev, mode, divisor1, divisor2);
- } else {
- devpriv->ai_et_div1 = divisor1;
- devpriv->ai_et_div2 = divisor2;
- }
- break;
- case 3:
+
+ if (cmd->start_src == TRIG_NOW)
+ pci171x_start_pacer(dev, true);
+ } else { /* TRIG_EXT */
devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
- break;
}
return 0;
@@ -1036,8 +971,7 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
const struct boardtype *this_board = comedi_board(dev);
struct pci1710_private *devpriv = dev->private;
int err = 0;
- int tmp;
- unsigned int divisor1 = 0, divisor2 = 0;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -1085,64 +1019,25 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
- i8253_cascade_ns_to_timer(devpriv->i8254_osc_base,
- &divisor1, &divisor2,
- &cmd->convert_arg, cmd->flags);
- if (cmd->convert_arg < this_board->ai_ns_min)
- cmd->convert_arg = this_board->ai_ns_min;
- if (tmp != cmd->convert_arg)
- err++;
+ arg = cmd->convert_arg;
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
+ &devpriv->next_divisor1,
+ &devpriv->next_divisor2,
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
}
if (err)
return 4;
- /* step 5: complain about special chanlist considerations */
-
- if (cmd->chanlist) {
- if (!check_channel_list(dev, s, cmd->chanlist,
- cmd->chanlist_len))
- return 5; /* incorrect channels list */
- }
-
- return 0;
-}
-
-/*
-==============================================================================
-*/
-static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- struct pci1710_private *devpriv = dev->private;
- struct comedi_cmd *cmd = &s->async->cmd;
-
- devpriv->ai_n_chan = cmd->chanlist_len;
- devpriv->ai_chanlist = cmd->chanlist;
- devpriv->ai_flags = cmd->flags;
- devpriv->ai_data_len = s->async->prealloc_bufsz;
- devpriv->ai_timer1 = 0;
- devpriv->ai_timer2 = 0;
-
- if (cmd->stop_src == TRIG_COUNT)
- devpriv->ai_scans = cmd->stop_arg;
- else
- devpriv->ai_scans = 0;
+ /* Step 5: check channel list */
+ err |= pci171x_ai_check_chanlist(dev, s, cmd);
- if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */
- if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */
- devpriv->ai_timer1 = cmd->convert_arg;
- return pci171x_ai_docmd_and_mode(cmd->start_src ==
- TRIG_EXT ? 2 : 1, dev,
- s);
- }
- if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
- return pci171x_ai_docmd_and_mode(3, dev, s);
- }
- }
+ if (err)
+ return 5;
- return -1;
+ return 0;
}
/*
@@ -1158,7 +1053,7 @@ static int pci171x_reset(struct comedi_device *dev)
outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */
outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
- start_pacer(dev, -1, 0, 0); /* stop 8254 */
+ pci171x_start_pacer(dev, false);
devpriv->da_ranges = 0;
if (this_board->n_aochan) {
outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */
@@ -1267,23 +1162,22 @@ static int pci1710_auto_attach(struct comedi_device *dev,
if (this_board->n_aichan) {
s = &dev->subdevices[subdev];
- dev->read_subdev = s;
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
if (this_board->n_aichand)
s->subdev_flags |= SDF_DIFF;
s->n_chan = this_board->n_aichan;
s->maxdata = this_board->ai_maxdata;
- s->len_chanlist = this_board->n_aichan;
s->range_table = this_board->rangelist_ai;
- s->cancel = pci171x_ai_cancel;
s->insn_read = pci171x_insn_read_ai;
if (dev->irq) {
+ dev->read_subdev = s;
s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = s->n_chan;
s->do_cmdtest = pci171x_ai_cmdtest;
s->do_cmd = pci171x_ai_cmd;
+ s->cancel = pci171x_ai_cancel;
}
- devpriv->i8254_osc_base = I8254_OSC_BASE_10MHZ;
subdev++;
}
@@ -1345,9 +1239,6 @@ static int pci1710_auto_attach(struct comedi_device *dev,
subdev++;
}
- dev_info(dev->class_dev, "%s attached, irq %sabled\n",
- dev->board_name, dev->irq ? "en" : "dis");
-
return 0;
}
@@ -1374,7 +1265,7 @@ static int adv_pci1710_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = {
+static const struct pci_device_id adv_pci1710_pci_table[] = {
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index bd4f781b4b2..07b107d1ab3 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -280,8 +280,6 @@ static int pci1723_auto_attach(struct comedi_device *dev,
pci1723_reset(dev);
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
@@ -306,7 +304,7 @@ static int adv_pci1723_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(adv_pci1723_pci_table) = {
+static const struct pci_device_id adv_pci1723_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c
index 009a3039fc4..af670acb03d 100644
--- a/drivers/staging/comedi/drivers/adv_pci1724.c
+++ b/drivers/staging/comedi/drivers/adv_pci1724.c
@@ -116,8 +116,8 @@ enum board_id_contents {
BOARD_ID_MASK = 0xf
};
-static const struct comedi_lrange ao_ranges_1724 = { 4,
- {
+static const struct comedi_lrange ao_ranges_1724 = {
+ 4, {
BIP_RANGE(10),
RANGE_mA(0, 20),
RANGE_mA(4, 20),
@@ -381,7 +381,7 @@ static int adv_pci1724_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(adv_pci1724_pci_table) = {
+static const struct pci_device_id adv_pci1724_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1724) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index 6bac665261f..2d966a87f2e 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -1130,10 +1130,12 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
for (i = 0; i < MAX_DIO_SUBDEVG; i++)
for (j = 0; j < this_board->sdio[i].regs; j++) {
s = &dev->subdevices[subdev];
- subdev_8255_init(dev, s, NULL,
- dev->iobase +
- this_board->sdio[i].addr +
- SIZE_8255 * j);
+ ret = subdev_8255_init(dev, s, NULL,
+ dev->iobase +
+ this_board->sdio[i].addr +
+ SIZE_8255 * j);
+ if (ret)
+ return ret;
subdev++;
}
@@ -1188,7 +1190,7 @@ static int adv_pci_dio_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &adv_pci_dio_driver, cardtype);
}
-static DEFINE_PCI_DEVICE_TABLE(adv_pci_dio_pci_table) = {
+static const struct pci_device_id adv_pci_dio_pci_table[] = {
{ PCI_VDEVICE(ADVANTECH, 0x1730), TYPE_PCI1730 },
{ PCI_VDEVICE(ADVANTECH, 0x1733), TYPE_PCI1733 },
{ PCI_VDEVICE(ADVANTECH, 0x1734), TYPE_PCI1734 },
diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c
index abb28498b58..324746b1493 100644
--- a/drivers/staging/comedi/drivers/aio_aio12_8.c
+++ b/drivers/staging/comedi/drivers/aio_aio12_8.c
@@ -101,14 +101,27 @@ struct aio12_8_private {
unsigned int ao_readback[4];
};
+static int aio_aio12_8_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + AIO12_8_STATUS_REG);
+ if (status & AIO12_8_STATUS_ADC_EOC)
+ return 0;
+ return -EBUSY;
+}
+
static int aio_aio12_8_ai_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int range = CR_RANGE(insn->chanspec);
- unsigned int val;
unsigned char control;
+ int ret;
int n;
/*
@@ -122,20 +135,13 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev,
inb(dev->iobase + AIO12_8_STATUS_REG);
for (n = 0; n < insn->n; n++) {
- int timeout = 5;
-
/* Setup and start conversion */
outb(control, dev->iobase + AIO12_8_ADC_REG);
/* Wait for conversion to complete */
- do {
- val = inb(dev->iobase + AIO12_8_STATUS_REG);
- timeout--;
- if (timeout == 0) {
- dev_err(dev->class_dev, "ADC timeout\n");
- return -ETIMEDOUT;
- }
- } while (!(val & AIO12_8_STATUS_ADC_EOC));
+ ret = comedi_timeout(dev, s, insn, aio_aio12_8_ai_eoc, 0);
+ if (ret)
+ return ret;
data[n] = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata;
}
@@ -181,13 +187,12 @@ static int aio_aio12_8_ao_write(struct comedi_device *dev,
}
static const struct comedi_lrange range_aio_aio12_8 = {
- 4,
- {
- UNI_RANGE(5),
- BIP_RANGE(5),
- UNI_RANGE(10),
- BIP_RANGE(10),
- }
+ 4, {
+ UNI_RANGE(5),
+ BIP_RANGE(5),
+ UNI_RANGE(10),
+ BIP_RANGE(10)
+ }
};
static int aio_aio12_8_attach(struct comedi_device *dev,
@@ -248,9 +253,6 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
/* 8254 counter/timer subdevice */
s->type = COMEDI_SUBD_UNUSED;
- dev_info(dev->class_dev, "%s: %s attached\n",
- dev->driver->driver_name, dev->board_name);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index 22b3dda135f..781104aa533 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -98,7 +98,7 @@ static int aio_iiro_16_attach(struct comedi_device *dev,
s->range_table = &range_digital;
s->insn_bits = aio_iiro_16_dio_insn_bits_read;
- return 1;
+ return 0;
}
static struct comedi_driver aio_iiro_16_driver = {
diff --git a/drivers/staging/comedi/drivers/amcc_s5933.h b/drivers/staging/comedi/drivers/amcc_s5933.h
index b810d5f3d97..2ba73644461 100644
--- a/drivers/staging/comedi/drivers/amcc_s5933.h
+++ b/drivers/staging/comedi/drivers/amcc_s5933.h
@@ -145,12 +145,12 @@
#define AINT_READ_COMPL 0x00008000
#define AINT_WRITE_COMPL 0x00004000
-#define AINT_OMB_ENABLE 0x00001000
-#define AINT_OMB_SELECT 0x00000c00
+#define AINT_OMB_ENABLE 0x00001000
+#define AINT_OMB_SELECT 0x00000c00
#define AINT_OMB_BYTE 0x00000300
-#define AINT_IMB_ENABLE 0x00000010
-#define AINT_IMB_SELECT 0x0000000c
+#define AINT_IMB_ENABLE 0x00000010
+#define AINT_IMB_SELECT 0x0000000c
#define AINT_IMB_BYTE 0x00000003
/* these are bits from various different registers, needs cleanup XXX */
diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c
index 2e4bf284d52..3edaa4028da 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200_common.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c
@@ -130,7 +130,6 @@ struct dio200_subdev_intr {
unsigned int enabled_isns;
unsigned int stopcount;
bool active:1;
- bool continuous:1;
};
static inline const struct dio200_layout *
@@ -259,7 +258,7 @@ static int dio200_start_intr(struct comedi_device *dev,
struct comedi_cmd *cmd = &s->async->cmd;
int retval = 0;
- if (!subpriv->continuous && subpriv->stopcount == 0) {
+ if (cmd->stop_src == TRIG_COUNT && subpriv->stopcount == 0) {
/* An empty acquisition! */
s->async->events |= COMEDI_CB_EOA;
subpriv->active = false;
@@ -281,22 +280,18 @@ static int dio200_start_intr(struct comedi_device *dev,
return retval;
}
-/*
- * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
- */
-static int
-dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int trignum)
+static int dio200_inttrig_start_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int trig_num)
{
- struct dio200_subdev_intr *subpriv;
+ struct dio200_subdev_intr *subpriv = s->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned long flags;
int event = 0;
- if (trignum != 0)
+ if (trig_num != cmd->start_arg)
return -EINVAL;
- subpriv = s->private;
-
spin_lock_irqsave(&subpriv->spinlock, flags);
s->async->inttrig = NULL;
if (subpriv->active)
@@ -315,18 +310,18 @@ static void dio200_read_scan_intr(struct comedi_device *dev,
unsigned int triggered)
{
struct dio200_subdev_intr *subpriv = s->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned short val;
- unsigned int n, ch, len;
+ unsigned int n, ch;
val = 0;
- len = s->async->cmd.chanlist_len;
- for (n = 0; n < len; n++) {
- ch = CR_CHAN(s->async->cmd.chanlist[n]);
+ for (n = 0; n < cmd->chanlist_len; n++) {
+ ch = CR_CHAN(cmd->chanlist[n]);
if (triggered & (1U << ch))
val |= (1U << n);
}
/* Write the scan to the buffer. */
- if (comedi_buf_put(s->async, val)) {
+ if (comedi_buf_put(s, val)) {
s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
} else {
/* Error! Stop acquisition. */
@@ -336,8 +331,7 @@ static void dio200_read_scan_intr(struct comedi_device *dev,
}
/* Check for end of acquisition. */
- if (!subpriv->continuous) {
- /* stop_src == TRIG_COUNT */
+ if (cmd->stop_src == TRIG_COUNT) {
if (subpriv->stopcount > 0) {
subpriv->stopcount--;
if (subpriv->stopcount == 0) {
@@ -513,31 +507,19 @@ static int dio200_subdev_intr_cmd(struct comedi_device *dev,
int event = 0;
spin_lock_irqsave(&subpriv->spinlock, flags);
- subpriv->active = 1;
+ subpriv->active = true;
/* Set up end of acquisition. */
- switch (cmd->stop_src) {
- case TRIG_COUNT:
- subpriv->continuous = false;
+ if (cmd->stop_src == TRIG_COUNT)
subpriv->stopcount = cmd->stop_arg;
- break;
- default:
- /* TRIG_NONE */
- subpriv->continuous = true;
+ else /* TRIG_NONE */
subpriv->stopcount = 0;
- break;
- }
- /* Set up start of acquisition. */
- switch (cmd->start_src) {
- case TRIG_INT:
+ if (cmd->start_src == TRIG_INT)
s->async->inttrig = dio200_inttrig_start_intr;
- break;
- default:
- /* TRIG_NOW */
+ else /* TRIG_NOW */
event = dio200_start_intr(dev, s);
- break;
- }
+
spin_unlock_irqrestore(&subpriv->spinlock, flags);
if (event)
@@ -829,7 +811,7 @@ dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
spin_lock_irqsave(&subpriv->spinlock, flags);
switch (data[0]) {
case INSN_CONFIG_SET_COUNTER_MODE:
- if (data[1] > (I8254_MODE5 | I8254_BINARY))
+ if (data[1] > (I8254_MODE5 | I8254_BCD))
ret = -EINVAL;
else
dio200_subdev_8254_set_mode(dev, s, chan, data[1]);
@@ -1208,7 +1190,7 @@ int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq,
"warning! irq %u unavailable!\n", irq);
}
}
- dev_info(dev->class_dev, "attached\n");
+
return 0;
}
EXPORT_SYMBOL_GPL(amplc_dio200_common_attach);
diff --git a/drivers/staging/comedi/drivers/amplc_dio200_pci.c b/drivers/staging/comedi/drivers/amplc_dio200_pci.c
index a810a241644..e0367380b37 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200_pci.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200_pci.c
@@ -439,7 +439,7 @@ static struct comedi_driver dio200_pci_comedi_driver = {
.detach = dio200_pci_detach,
};
-static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
+static const struct pci_device_id dio200_pci_table[] = {
{
PCI_VDEVICE(AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215),
pci215_model
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index 98075f999c9..c9a96ad0055 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236.c
@@ -314,7 +314,7 @@ static int pc236_intr_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
- err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
if (err)
@@ -356,44 +356,18 @@ static int pc236_intr_cancel(struct comedi_device *dev,
static irqreturn_t pc236_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
- struct comedi_subdevice *s = &dev->subdevices[1];
+ struct comedi_subdevice *s = dev->read_subdev;
int handled;
handled = pc236_intr_check(dev);
if (dev->attached && handled) {
- comedi_buf_put(s->async, 0);
+ comedi_buf_put(s, 0);
s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
comedi_event(dev, s);
}
return IRQ_RETVAL(handled);
}
-static void pc236_report_attach(struct comedi_device *dev, unsigned int irq)
-{
- const struct pc236_board *thisboard = comedi_board(dev);
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- char tmpbuf[60];
- int tmplen;
-
- if (is_isa_board(thisboard))
- tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
- "(base %#lx) ", dev->iobase);
- else if (is_pci_board(thisboard))
- tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
- "(pci %s) ", pci_name(pcidev));
- else
- tmplen = 0;
- if (irq)
- tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
- "(irq %u%s) ", irq,
- (dev->irq ? "" : " UNAVAILABLE"));
- else
- tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
- "(no irq) ");
- dev_info(dev->class_dev, "%s %sattached\n",
- dev->board_name, tmpbuf);
-}
-
static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase,
unsigned int irq, unsigned long req_irq_flags)
{
@@ -411,10 +385,9 @@ static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase,
s = &dev->subdevices[0];
/* digital i/o subdevice (8255) */
ret = subdev_8255_init(dev, s, NULL, iobase);
- if (ret < 0) {
- dev_err(dev->class_dev, "error! out of memory!\n");
+ if (ret)
return ret;
- }
+
s = &dev->subdevices[1];
dev->read_subdev = s;
s->type = COMEDI_SUBD_UNUSED;
@@ -429,13 +402,14 @@ static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase,
s->maxdata = 1;
s->range_table = &range_digital;
s->insn_bits = pc236_intr_insn;
+ s->len_chanlist = 1;
s->do_cmdtest = pc236_intr_cmdtest;
s->do_cmd = pc236_intr_cmd;
s->cancel = pc236_intr_cancel;
}
}
- pc236_report_attach(dev, irq);
- return 1;
+
+ return 0;
}
static int pc236_pci_common_attach(struct comedi_device *dev,
@@ -567,7 +541,7 @@ static struct comedi_driver amplc_pc236_driver = {
};
#if DO_PCI
-static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = {
+static const struct pci_device_id pc236_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236) },
{0}
};
diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c
index 5b4b5ab34e2..7c10d28d278 100644
--- a/drivers/staging/comedi/drivers/amplc_pc263.c
+++ b/drivers/staging/comedi/drivers/amplc_pc263.c
@@ -94,8 +94,6 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* read initial relay state */
s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8);
- dev_info(dev->class_dev, "%s (base %#lx) attached\n", dev->board_name,
- dev->iobase);
return 0;
}
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index 810e397d8fd..339c47c1eb9 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -267,17 +267,16 @@ Caveats:
/* The software selectable internal ranges for PCI224 (option[2] == 0). */
static const struct comedi_lrange range_pci224_internal = {
- 8,
- {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25),
- }
+ 8, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
static const unsigned short hwrange_pci224_internal[8] = {
@@ -293,11 +292,10 @@ static const unsigned short hwrange_pci224_internal[8] = {
/* The software selectable external ranges for PCI224 (option[2] == 1). */
static const struct comedi_lrange range_pci224_external = {
- 2,
- {
- RANGE_ext(-1, 1), /* bipolar [-Vref,+Vref] */
- RANGE_ext(0, 1), /* unipolar [0,+Vref] */
- }
+ 2, {
+ RANGE_ext(-1, 1), /* bipolar [-Vref,+Vref] */
+ RANGE_ext(0, 1) /* unipolar [0,+Vref] */
+ }
};
static const unsigned short hwrange_pci224_external[2] = {
@@ -308,19 +306,17 @@ static const unsigned short hwrange_pci224_external[2] = {
/* The hardware selectable Vref*2 external range for PCI234
* (option[2] == 1, option[3+n] == 0). */
static const struct comedi_lrange range_pci234_ext2 = {
- 1,
- {
- RANGE_ext(-2, 2),
- }
+ 1, {
+ RANGE_ext(-2, 2)
+ }
};
/* The hardware selectable Vref external range for PCI234
* (option[2] == 1, option[3+n] == 1). */
static const struct comedi_lrange range_pci234_ext = {
- 1,
- {
- RANGE_ext(-1, 1),
- }
+ 1, {
+ RANGE_ext(-1, 1)
+ }
};
/* This serves for all the PCI234 ranges. */
@@ -381,7 +377,6 @@ struct pci224_private {
unsigned int cached_div1;
unsigned int cached_div2;
unsigned int ao_stop_count;
- short ao_stop_continuous;
unsigned short ao_enab; /* max 16 channels so 'short' will do */
unsigned char intsce;
};
@@ -471,16 +466,6 @@ pci224_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
}
/*
- * Just a wrapper for the inline function 'i8253_cascade_ns_to_timer'.
- */
-static void
-pci224_cascade_ns_to_timer(int osc_base, unsigned int *d1, unsigned int *d2,
- unsigned int *nanosec, int round_mode)
-{
- i8253_cascade_ns_to_timer(osc_base, d1, d2, nanosec, round_mode);
-}
-
-/*
* Kills a command running on the AO subdevice.
*/
static void pci224_ao_stop(struct comedi_device *dev,
@@ -535,11 +520,10 @@ static void pci224_ao_start(struct comedi_device *dev,
unsigned long flags;
set_bit(AO_CMD_STARTED, &devpriv->state);
- if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) {
+ if (cmd->stop_src == TRIG_COUNT && devpriv->ao_stop_count == 0) {
/* An empty acquisition! */
- pci224_ao_stop(dev, s);
s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
} else {
/* Enable interrupts. */
spin_lock_irqsave(&devpriv->ao_spinlock, flags);
@@ -561,21 +545,15 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev,
{
struct pci224_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int bytes_per_scan = cfc_bytes_per_scan(s);
unsigned int num_scans;
unsigned int room;
unsigned short dacstat;
unsigned int i, n;
- unsigned int bytes_per_scan;
- if (cmd->chanlist_len) {
- bytes_per_scan = cmd->chanlist_len * sizeof(short);
- } else {
- /* Shouldn't get here! */
- bytes_per_scan = sizeof(short);
- }
/* Determine number of scans available in buffer. */
- num_scans = comedi_buf_read_n_available(s->async) / bytes_per_scan;
- if (!devpriv->ao_stop_continuous) {
+ num_scans = comedi_buf_read_n_available(s) / bytes_per_scan;
+ if (cmd->stop_src == TRIG_COUNT) {
/* Fixed number of scans. */
if (num_scans > devpriv->ao_stop_count)
num_scans = devpriv->ao_stop_count;
@@ -587,11 +565,10 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev,
switch (dacstat & PCI224_DACCON_FIFOFL_MASK) {
case PCI224_DACCON_FIFOFL_EMPTY:
room = PCI224_FIFO_ROOM_EMPTY;
- if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) {
+ if (cmd->stop_src == TRIG_COUNT && devpriv->ao_stop_count == 0) {
/* FIFO empty at end of counted acquisition. */
- pci224_ao_stop(dev, s);
s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
break;
@@ -609,14 +586,12 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev,
/* FIFO is less than half-full. */
if (num_scans == 0) {
/* Nothing left to put in the FIFO. */
- pci224_ao_stop(dev, s);
- s->async->events |= COMEDI_CB_OVERFLOW;
dev_err(dev->class_dev, "AO buffer underrun\n");
+ s->async->events |= COMEDI_CB_OVERFLOW;
}
}
/* Determine how many new scans can be put in the FIFO. */
- if (cmd->chanlist_len)
- room /= cmd->chanlist_len;
+ room /= cmd->chanlist_len;
/* Determine how many scans to process. */
if (num_scans > room)
@@ -631,7 +606,7 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev,
dev->iobase + PCI224_DACDATA);
}
}
- if (!devpriv->ao_stop_continuous) {
+ if (cmd->stop_src == TRIG_COUNT) {
devpriv->ao_stop_count -= num_scans;
if (devpriv->ao_stop_count == 0) {
/*
@@ -674,19 +649,17 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev,
PCI224_DACCON_TRIG_MASK);
outw(devpriv->daccon, dev->iobase + PCI224_DACCON);
}
- if (s->async->events)
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
-/*
- * Internal trigger function to start acquisition on AO subdevice.
- */
-static int
-pci224_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int trignum)
+static int pci224_ao_inttrig_start(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int trig_num)
{
- if (trignum != 0)
+ struct comedi_cmd *cmd = &s->async->cmd;
+
+ if (trig_num != cmd->start_arg)
return -EINVAL;
s->async->inttrig = NULL;
@@ -695,6 +668,37 @@ pci224_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s,
return 1;
}
+static int pci224_ao_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
+ unsigned int chan_mask = 0;
+ int i;
+
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+ unsigned int range = CR_RANGE(cmd->chanlist[i]);
+
+ if (chan_mask & (1 << chan)) {
+ dev_dbg(dev->class_dev,
+ "%s: entries in chanlist must contain no duplicate channels\n",
+ __func__);
+ return -EINVAL;
+ }
+ chan_mask |= (1 << chan);
+
+ if (range != range0) {
+ dev_dbg(dev->class_dev,
+ "%s: entries in chanlist must all have the same range index\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
#define MAX_SCAN_PERIOD 0xFFFFFFFFU
#define MIN_SCAN_PERIOD 2500
#define CONVERT_PERIOD 625
@@ -708,7 +712,7 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
{
struct pci224_private *devpriv = dev->private;
int err = 0;
- unsigned int tmp;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -735,14 +739,14 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
* There's only one external trigger signal (which makes these
* tests easier). Only one thing can use it.
*/
- tmp = 0;
+ arg = 0;
if (cmd->start_src & TRIG_EXT)
- tmp++;
+ arg++;
if (cmd->scan_begin_src & TRIG_EXT)
- tmp++;
+ arg++;
if (cmd->stop_src & TRIG_EXT)
- tmp++;
- if (tmp > 1)
+ arg++;
+ if (arg > 1)
err |= -EINVAL;
if (err)
@@ -775,10 +779,10 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
MAX_SCAN_PERIOD);
- tmp = cmd->chanlist_len * CONVERT_PERIOD;
- if (tmp < MIN_SCAN_PERIOD)
- tmp = MIN_SCAN_PERIOD;
- err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, tmp);
+ arg = cmd->chanlist_len * CONVERT_PERIOD;
+ if (arg < MIN_SCAN_PERIOD)
+ arg = MIN_SCAN_PERIOD;
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, arg);
break;
case TRIG_EXT:
/* Force to external trigger 0. */
@@ -829,100 +833,21 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
/* Step 4: fix up any arguments. */
if (cmd->scan_begin_src == TRIG_TIMER) {
- unsigned int div1, div2, round;
- int round_mode = cmd->flags & TRIG_ROUND_MASK;
-
- tmp = cmd->scan_begin_arg;
- /* Check whether to use a single timer. */
- switch (round_mode) {
- case TRIG_ROUND_NEAREST:
- default:
- round = I8254_OSC_BASE_10MHZ / 2;
- break;
- case TRIG_ROUND_DOWN:
- round = 0;
- break;
- case TRIG_ROUND_UP:
- round = I8254_OSC_BASE_10MHZ - 1;
- break;
- }
- /* Be careful to avoid overflow! */
- div2 = cmd->scan_begin_arg / I8254_OSC_BASE_10MHZ;
- div2 += (round + cmd->scan_begin_arg % I8254_OSC_BASE_10MHZ) /
- I8254_OSC_BASE_10MHZ;
- if (div2 <= 0x10000) {
- /* A single timer will suffice. */
- if (div2 < 2)
- div2 = 2;
- cmd->scan_begin_arg = div2 * I8254_OSC_BASE_10MHZ;
- if (cmd->scan_begin_arg < div2 ||
- cmd->scan_begin_arg < I8254_OSC_BASE_10MHZ) {
- /* Overflow! */
- cmd->scan_begin_arg = MAX_SCAN_PERIOD;
- }
- } else {
- /* Use two timers. */
- div1 = devpriv->cached_div1;
- div2 = devpriv->cached_div2;
- pci224_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
- &div1, &div2,
- &cmd->scan_begin_arg,
- round_mode);
- devpriv->cached_div1 = div1;
- devpriv->cached_div2 = div2;
- }
- if (tmp != cmd->scan_begin_arg)
- err++;
-
+ arg = cmd->scan_begin_arg;
+ /* Use two timers. */
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
+ &devpriv->cached_div1,
+ &devpriv->cached_div2,
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
if (err)
return 4;
- /* Step 5: check channel list. */
-
- if (cmd->chanlist && (cmd->chanlist_len > 0)) {
- unsigned int range;
- enum { range_err = 1, dupchan_err = 2, };
- unsigned errors;
- unsigned int n;
- unsigned int ch;
-
- /*
- * Check all channels have the same range index. Don't care
- * about analogue reference, as we can't configure it.
- *
- * Check the list has no duplicate channels.
- */
- range = CR_RANGE(cmd->chanlist[0]);
- errors = 0;
- tmp = 0;
- for (n = 0; n < cmd->chanlist_len; n++) {
- ch = CR_CHAN(cmd->chanlist[n]);
- if (tmp & (1U << ch))
- errors |= dupchan_err;
-
- tmp |= (1U << ch);
- if (CR_RANGE(cmd->chanlist[n]) != range)
- errors |= range_err;
-
- }
- if (errors) {
- if (errors & dupchan_err) {
- DPRINTK("comedi%d: " DRIVER_NAME
- ": ao_cmdtest: "
- "entries in chanlist must contain no "
- "duplicate channels\n", dev->minor);
- }
- if (errors & range_err) {
- DPRINTK("comedi%d: " DRIVER_NAME
- ": ao_cmdtest: "
- "entries in chanlist must all have "
- "the same range index\n", dev->minor);
- }
- err++;
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= pci224_ao_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -930,9 +855,33 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
-/*
- * 'do_cmd' function for AO subdevice.
- */
+static void pci224_ao_start_pacer(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct pci224_private *devpriv = dev->private;
+ unsigned long timer_base = devpriv->iobase1 + PCI224_Z2_CT0;
+
+ /*
+ * The output of timer Z2-0 will be used as the scan trigger
+ * source.
+ */
+ /* Make sure Z2-0 is gated on. */
+ outb(GAT_CONFIG(0, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE);
+ /* Cascading with Z2-2. */
+ /* Make sure Z2-2 is gated on. */
+ outb(GAT_CONFIG(2, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE);
+ /* Z2-2 needs 10 MHz clock. */
+ outb(CLK_CONFIG(2, CLK_10MHZ), devpriv->iobase1 + PCI224_ZCLK_SCE);
+ /* Load Z2-2 mode (2) and counter (div1). */
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
+ i8254_write(timer_base, 0, 2, devpriv->cached_div1);
+ /* Z2-0 is clocked from Z2-2's output. */
+ outb(CLK_CONFIG(0, CLK_OUTNM1), devpriv->iobase1 + PCI224_ZCLK_SCE);
+ /* Load Z2-0 mode (2) and counter (div2). */
+ i8254_set_mode(timer_base, 0, 0, I8254_MODE2 | I8254_BINARY);
+ i8254_write(timer_base, 0, 0, devpriv->cached_div2);
+}
+
static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct pci224_private *devpriv = dev->private;
@@ -988,106 +937,26 @@ static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
dev->iobase + PCI224_DACCON);
- if (cmd->scan_begin_src == TRIG_TIMER) {
- unsigned int div1, div2, round;
- unsigned int ns = cmd->scan_begin_arg;
- int round_mode = cmd->flags & TRIG_ROUND_MASK;
-
- /* Check whether to use a single timer. */
- switch (round_mode) {
- case TRIG_ROUND_NEAREST:
- default:
- round = I8254_OSC_BASE_10MHZ / 2;
- break;
- case TRIG_ROUND_DOWN:
- round = 0;
- break;
- case TRIG_ROUND_UP:
- round = I8254_OSC_BASE_10MHZ - 1;
- break;
- }
- /* Be careful to avoid overflow! */
- div2 = cmd->scan_begin_arg / I8254_OSC_BASE_10MHZ;
- div2 += (round + cmd->scan_begin_arg % I8254_OSC_BASE_10MHZ) /
- I8254_OSC_BASE_10MHZ;
- if (div2 <= 0x10000) {
- /* A single timer will suffice. */
- if (div2 < 2)
- div2 = 2;
- div2 &= 0xffff;
- div1 = 1; /* Flag that single timer to be used. */
- } else {
- /* Use two timers. */
- div1 = devpriv->cached_div1;
- div2 = devpriv->cached_div2;
- pci224_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
- &div1, &div2,
- &ns, round_mode);
- }
-
- /*
- * The output of timer Z2-0 will be used as the scan trigger
- * source.
- */
- /* Make sure Z2-0 is gated on. */
- outb(GAT_CONFIG(0, GAT_VCC),
- devpriv->iobase1 + PCI224_ZGAT_SCE);
- if (div1 == 1) {
- /* Not cascading. Z2-0 needs 10 MHz clock. */
- outb(CLK_CONFIG(0, CLK_10MHZ),
- devpriv->iobase1 + PCI224_ZCLK_SCE);
- } else {
- /* Cascading with Z2-2. */
- /* Make sure Z2-2 is gated on. */
- outb(GAT_CONFIG(2, GAT_VCC),
- devpriv->iobase1 + PCI224_ZGAT_SCE);
- /* Z2-2 needs 10 MHz clock. */
- outb(CLK_CONFIG(2, CLK_10MHZ),
- devpriv->iobase1 + PCI224_ZCLK_SCE);
- /* Load Z2-2 mode (2) and counter (div1). */
- i8254_load(devpriv->iobase1 + PCI224_Z2_CT0, 0,
- 2, div1, 2);
- /* Z2-0 is clocked from Z2-2's output. */
- outb(CLK_CONFIG(0, CLK_OUTNM1),
- devpriv->iobase1 + PCI224_ZCLK_SCE);
- }
- /* Load Z2-0 mode (2) and counter (div2). */
- i8254_load(devpriv->iobase1 + PCI224_Z2_CT0, 0, 0, div2, 2);
- }
+ if (cmd->scan_begin_src == TRIG_TIMER)
+ pci224_ao_start_pacer(dev, s);
/*
* Sort out end of acquisition.
*/
- switch (cmd->stop_src) {
- case TRIG_COUNT:
- /* Fixed number of scans. */
- devpriv->ao_stop_continuous = 0;
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->ao_stop_count = cmd->stop_arg;
- break;
- default:
- /* Continuous scans. */
- devpriv->ao_stop_continuous = 1;
+ else /* TRIG_EXT | TRIG_NONE */
devpriv->ao_stop_count = 0;
- break;
- }
- /*
- * Sort out start of acquisition.
- */
- switch (cmd->start_src) {
- case TRIG_INT:
- spin_lock_irqsave(&devpriv->ao_spinlock, flags);
- s->async->inttrig = &pci224_ao_inttrig_start;
- spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
- break;
- case TRIG_EXT:
+ spin_lock_irqsave(&devpriv->ao_spinlock, flags);
+ if (cmd->start_src == TRIG_INT) {
+ s->async->inttrig = pci224_ao_inttrig_start;
+ } else { /* TRIG_EXT */
/* Enable external interrupt trigger to start acquisition. */
- spin_lock_irqsave(&devpriv->ao_spinlock, flags);
devpriv->intsce |= PCI224_INTR_EXT;
outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE);
- spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
- break;
}
+ spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
return 0;
}
@@ -1111,7 +980,7 @@ pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
{
const struct pci224_board *thisboard = comedi_board(dev);
struct pci224_private *devpriv = dev->private;
- struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned short *array = data;
unsigned int length = num_bytes / sizeof(*array);
unsigned int offset;
@@ -1121,7 +990,7 @@ pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
/* The hardware expects 16-bit numbers. */
shift = 16 - thisboard->ao_bits;
/* Channels will be all bipolar or all unipolar. */
- if ((devpriv->hwrange[CR_RANGE(async->cmd.chanlist[0])] &
+ if ((devpriv->hwrange[CR_RANGE(cmd->chanlist[0])] &
PCI224_DACCON_POLAR_MASK) == PCI224_DACCON_POLAR_UNI) {
/* Unipolar */
offset = 0;
@@ -1142,7 +1011,7 @@ static irqreturn_t pci224_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct pci224_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
+ struct comedi_subdevice *s = dev->write_subdev;
struct comedi_cmd *cmd;
unsigned char intstat, valid_intstat;
unsigned char curenab;
@@ -1243,20 +1112,6 @@ static struct pci_dev *pci224_find_pci_dev(struct comedi_device *dev,
return NULL;
}
-static void pci224_report_attach(struct comedi_device *dev, unsigned int irq)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- char tmpbuf[30];
-
- if (irq)
- snprintf(tmpbuf, sizeof(tmpbuf), "irq %u%s", irq,
- (dev->irq ? "" : " UNAVAILABLE"));
- else
- snprintf(tmpbuf, sizeof(tmpbuf), "no irq");
- dev_info(dev->class_dev, "%s (pci %s) (%s) attached\n",
- dev->board_name, pci_name(pcidev), tmpbuf);
-}
-
/*
* Common part of attach and auto_attach.
*/
@@ -1405,8 +1260,7 @@ static int pci224_attach_common(struct comedi_device *dev,
}
}
- pci224_report_attach(dev, irq);
- return 1;
+ return 0;
}
static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -1498,7 +1352,7 @@ static int amplc_pci224_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(amplc_pci224_pci_table) = {
+static const struct pci_device_id amplc_pci224_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) },
{ 0 }
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index a97bbd6ca3d..3895bc7cb3e 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -519,14 +519,6 @@ struct pci230_private {
* level threshold (PCI230+/260+). */
unsigned short adcg; /* ADCG register value. */
unsigned char int_en; /* Interrupt enables bits. */
- unsigned char ai_continuous; /* Flag set when cmd->stop_src ==
- * TRIG_NONE - user chooses to stop
- * continuous conversion by
- * cancelation. */
- unsigned char ao_continuous; /* Flag set when cmd->stop_src ==
- * TRIG_NONE - user chooses to stop
- * continuous conversion by
- * cancelation. */
unsigned char ai_bipolar; /* Set if bipolar input range so we
* know to mangle it. */
unsigned char ao_bipolar; /* Set if bipolar output range so we
@@ -546,15 +538,16 @@ static const unsigned int pci230_timebase[8] = {
};
/* PCI230 analogue input range table */
-static const struct comedi_lrange pci230_ai_range = { 7, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5)
- }
+static const struct comedi_lrange pci230_ai_range = {
+ 7, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5)
+ }
};
/* PCI230 analogue gain bits for each input range. */
@@ -564,10 +557,11 @@ static const unsigned char pci230_ai_gain[7] = { 0, 1, 2, 3, 1, 2, 3 };
static const unsigned char pci230_ai_bipolar[7] = { 1, 1, 1, 1, 0, 0, 0 };
/* PCI230 analogue output range table */
-static const struct comedi_lrange pci230_ao_range = { 2, {
- UNI_RANGE(10),
- BIP_RANGE(10)
- }
+static const struct comedi_lrange pci230_ao_range = {
+ 2, {
+ UNI_RANGE(10),
+ BIP_RANGE(10)
+ }
};
/* PCI230 daccon bipolar flag for each analogue output range. */
@@ -797,19 +791,29 @@ static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct)
/* Counter ct, 8254 mode 1, initial count not written. */
}
-/*
- * COMEDI_SUBD_AI instruction;
- */
+static int pci230_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + PCI230_ADCCON);
+ if ((status & PCI230_ADC_FIFO_EMPTY) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int pci230_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
struct pci230_private *devpriv = dev->private;
- unsigned int n, i;
+ unsigned int n;
unsigned int chan, range, aref;
unsigned int gainshift;
- unsigned int status;
unsigned short adccon, adcen;
+ int ret;
/* Unpack channel and range. */
chan = CR_CHAN(insn->chanspec);
@@ -818,9 +822,9 @@ static int pci230_ai_rinsn(struct comedi_device *dev,
if (aref == AREF_DIFF) {
/* Differential. */
if (chan >= s->n_chan / 2) {
- DPRINTK("comedi%d: amplc_pci230: ai_rinsn: "
- "differential channel number out of range "
- "0 to %u\n", dev->minor, (s->n_chan / 2) - 1);
+ dev_dbg(dev->class_dev,
+ "%s: differential channel number out of range 0 to %u\n",
+ __func__, (s->n_chan / 2) - 1);
return -EINVAL;
}
}
@@ -881,18 +885,10 @@ static int pci230_ai_rinsn(struct comedi_device *dev,
i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
I8254_MODE1);
-#define TIMEOUT 100
/* wait for conversion to end */
- for (i = 0; i < TIMEOUT; i++) {
- status = inw(dev->iobase + PCI230_ADCCON);
- if (!(status & PCI230_ADC_FIFO_EMPTY))
- break;
- udelay(1);
- }
- if (i == TIMEOUT) {
- dev_err(dev->class_dev, "timeout\n");
- return -ETIMEDOUT;
- }
+ ret = comedi_timeout(dev, s, insn, pci230_ai_eoc, 0);
+ if (ret)
+ return ret;
/* read data */
data[n] = pci230_ai_read(dev);
@@ -949,6 +945,38 @@ static int pci230_ao_rinsn(struct comedi_device *dev,
return i;
}
+static int pci230_ao_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ unsigned int prev_chan = CR_CHAN(cmd->chanlist[0]);
+ unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
+ int i;
+
+ for (i = 1; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+ unsigned int range = CR_RANGE(cmd->chanlist[i]);
+
+ if (chan < prev_chan) {
+ dev_dbg(dev->class_dev,
+ "%s: channel numbers must increase\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (range != range0) {
+ dev_dbg(dev->class_dev,
+ "%s: channels must have the same range\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ prev_chan = chan;
+ }
+
+ return 0;
+}
+
static int pci230_ao_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
@@ -1061,48 +1089,9 @@ static int pci230_ao_cmdtest(struct comedi_device *dev,
if (err)
return 4;
- /* Step 5: check channel list if it exists. */
-
- if (cmd->chanlist && cmd->chanlist_len > 0) {
- enum {
- seq_err = (1 << 0),
- range_err = (1 << 1)
- };
- unsigned int errors;
- unsigned int n;
- unsigned int chan, prev_chan;
- unsigned int range, first_range;
-
- prev_chan = CR_CHAN(cmd->chanlist[0]);
- first_range = CR_RANGE(cmd->chanlist[0]);
- errors = 0;
- for (n = 1; n < cmd->chanlist_len; n++) {
- chan = CR_CHAN(cmd->chanlist[n]);
- range = CR_RANGE(cmd->chanlist[n]);
- /* Channel numbers must strictly increase. */
- if (chan < prev_chan)
- errors |= seq_err;
-
- /* Ranges must be the same. */
- if (range != first_range)
- errors |= range_err;
-
- prev_chan = chan;
- }
- if (errors != 0) {
- err++;
- if ((errors & seq_err) != 0) {
- DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: "
- "channel numbers must increase\n",
- dev->minor);
- }
- if ((errors & range_err) != 0) {
- DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: "
- "channels must have the same range\n",
- dev->minor);
- }
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= pci230_ao_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -1171,11 +1160,11 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev,
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
- if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0))
+ if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0)
return;
for (i = 0; i < cmd->chanlist_len; i++) {
/* Read sample from Comedi's circular buffer. */
- ret = comedi_buf_get(s->async, &data);
+ ret = comedi_buf_get(s, &data);
if (ret == 0) {
s->async->events |= COMEDI_CB_OVERFLOW;
pci230_ao_stop(dev, s);
@@ -1186,7 +1175,7 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev,
pci230_ao_write_nofifo(dev, data, CR_CHAN(cmd->chanlist[i]));
}
async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
- if (!devpriv->ao_continuous) {
+ if (cmd->stop_src == TRIG_COUNT) {
devpriv->ao_scan_count--;
if (devpriv->ao_scan_count == 0) {
/* End of acquisition. */
@@ -1208,16 +1197,14 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev,
unsigned int room;
unsigned short dacstat;
unsigned int i, n;
- unsigned int bytes_per_scan;
unsigned int events = 0;
int running;
/* Get DAC FIFO status. */
dacstat = inw(dev->iobase + PCI230_DACCON);
/* Determine number of scans available in buffer. */
- bytes_per_scan = cmd->chanlist_len * sizeof(short);
- num_scans = comedi_buf_read_n_available(async) / bytes_per_scan;
- if (!devpriv->ao_continuous) {
+ num_scans = comedi_buf_read_n_available(s) / cfc_bytes_per_scan(s);
+ if (cmd->stop_src == TRIG_COUNT) {
/* Fixed number of scans. */
if (num_scans > devpriv->ao_scan_count)
num_scans = devpriv->ao_scan_count;
@@ -1261,13 +1248,13 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev,
for (i = 0; i < cmd->chanlist_len; i++) {
unsigned short datum;
- comedi_buf_get(async, &datum);
+ comedi_buf_get(s, &datum);
pci230_ao_write_fifo(dev, datum,
CR_CHAN(cmd->chanlist[i]));
}
}
events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK;
- if (!devpriv->ao_continuous) {
+ if (cmd->stop_src == TRIG_COUNT) {
devpriv->ao_scan_count -= num_scans;
if (devpriv->ao_scan_count == 0) {
/* All data for the command has been written
@@ -1345,7 +1332,7 @@ static void pci230_ao_start(struct comedi_device *dev,
unsigned long irqflags;
set_bit(AO_CMD_STARTED, &devpriv->state);
- if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0)) {
+ if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0) {
/* An empty acquisition! */
async->events |= COMEDI_CB_EOA;
pci230_ao_stop(dev, s);
@@ -1430,7 +1417,9 @@ static int pci230_ao_inttrig_start(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int trig_num)
{
- if (trig_num != 0)
+ struct comedi_cmd *cmd = &s->async->cmd;
+
+ if (trig_num != cmd->start_src)
return -EINVAL;
s->async->inttrig = NULL;
@@ -1456,14 +1445,10 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
/* Get number of scans required. */
- if (cmd->stop_src == TRIG_COUNT) {
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->ao_scan_count = cmd->stop_arg;
- devpriv->ao_continuous = 0;
- } else {
- /* TRIG_NONE, user calls cancel. */
+ else /* TRIG_NONE, user calls cancel */
devpriv->ao_scan_count = 0;
- devpriv->ao_continuous = 1;
- }
/* Set range - see analogue output range table; 0 => unipolar 10V,
* 1 => bipolar +/-10V range scale */
@@ -1548,6 +1533,109 @@ static int pci230_ai_check_scan_period(struct comedi_cmd *cmd)
return !err;
}
+static int pci230_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ struct pci230_private *devpriv = dev->private;
+ unsigned int max_diff_chan = (s->n_chan / 2) - 1;
+ unsigned int prev_chan = 0;
+ unsigned int prev_range = 0;
+ unsigned int prev_aref = 0;
+ unsigned int prev_polarity = 0;
+ unsigned int subseq_len = 0;
+ int i;
+
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chanspec = cmd->chanlist[i];
+ unsigned int chan = CR_CHAN(chanspec);
+ unsigned int range = CR_RANGE(chanspec);
+ unsigned int aref = CR_AREF(chanspec);
+ unsigned int polarity = pci230_ai_bipolar[range];
+
+ if (aref == AREF_DIFF && chan >= max_diff_chan) {
+ dev_dbg(dev->class_dev,
+ "%s: differential channel number out of range 0 to %u\n",
+ __func__, max_diff_chan);
+ return -EINVAL;
+ }
+
+ if (i > 0) {
+ /*
+ * Channel numbers must strictly increase or
+ * subsequence must repeat exactly.
+ */
+ if (chan <= prev_chan && subseq_len == 0)
+ subseq_len = i;
+
+ if (subseq_len > 0 &&
+ cmd->chanlist[i % subseq_len] != chanspec) {
+ dev_dbg(dev->class_dev,
+ "%s: channel numbers must increase or sequence must repeat exactly\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (aref != prev_aref) {
+ dev_dbg(dev->class_dev,
+ "%s: channel sequence analogue references must be all the same (single-ended or differential)\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (polarity != prev_polarity) {
+ dev_dbg(dev->class_dev,
+ "%s: channel sequence ranges must be all bipolar or all unipolar\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (aref != AREF_DIFF && range != prev_range &&
+ ((chan ^ prev_chan) & ~1) == 0) {
+ dev_dbg(dev->class_dev,
+ "%s: single-ended channel pairs must have the same range\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+ prev_chan = chan;
+ prev_range = range;
+ prev_aref = aref;
+ prev_polarity = polarity;
+ }
+
+ if (subseq_len == 0)
+ subseq_len = cmd->chanlist_len;
+
+ if ((cmd->chanlist_len % subseq_len) != 0) {
+ dev_dbg(dev->class_dev,
+ "%s: sequence must repeat exactly\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Buggy PCI230+ or PCI260+ requires channel 0 to be (first) in the
+ * sequence if the sequence contains more than one channel. Hardware
+ * versions 1 and 2 have the bug. There is no hardware version 3.
+ *
+ * Actually, there are two firmwares that report themselves as
+ * hardware version 1 (the boards have different ADC chips with
+ * slightly different timing requirements, which was supposed to
+ * be invisible to software). The first one doesn't seem to have
+ * the bug, but the second one does, and we can't tell them apart!
+ */
+ if (devpriv->hwver > 0 && devpriv->hwver < 4) {
+ if (subseq_len > 1 && CR_CHAN(cmd->chanlist[0]) != 0) {
+ dev_info(dev->class_dev,
+ "amplc_pci230: ai_cmdtest: Buggy PCI230+/260+ h/w version %u requires first channel of multi-channel sequence to be 0 (corrected in h/w version 4)\n",
+ devpriv->hwver);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int pci230_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
@@ -1736,140 +1824,9 @@ static int pci230_ai_cmdtest(struct comedi_device *dev,
if (err)
return 4;
- /* Step 5: check channel list if it exists. */
-
- if (cmd->chanlist && cmd->chanlist_len > 0) {
- enum {
- seq_err = 1 << 0,
- rangepair_err = 1 << 1,
- polarity_err = 1 << 2,
- aref_err = 1 << 3,
- diffchan_err = 1 << 4,
- buggy_chan0_err = 1 << 5
- };
- unsigned int errors;
- unsigned int chan, prev_chan;
- unsigned int range, prev_range;
- unsigned int polarity, prev_polarity;
- unsigned int aref, prev_aref;
- unsigned int subseq_len;
- unsigned int n;
-
- subseq_len = 0;
- errors = 0;
- prev_chan = prev_aref = prev_range = prev_polarity = 0;
- for (n = 0; n < cmd->chanlist_len; n++) {
- chan = CR_CHAN(cmd->chanlist[n]);
- range = CR_RANGE(cmd->chanlist[n]);
- aref = CR_AREF(cmd->chanlist[n]);
- polarity = pci230_ai_bipolar[range];
- /* Only the first half of the channels are available if
- * differential. (These are remapped in software. In
- * hardware, only the even channels are available.) */
- if ((aref == AREF_DIFF)
- && (chan >= (s->n_chan / 2))) {
- errors |= diffchan_err;
- }
- if (n > 0) {
- /* Channel numbers must strictly increase or
- * subsequence must repeat exactly. */
- if ((chan <= prev_chan)
- && (subseq_len == 0)) {
- subseq_len = n;
- }
- if ((subseq_len > 0)
- && (cmd->chanlist[n] !=
- cmd->chanlist[n % subseq_len])) {
- errors |= seq_err;
- }
- /* Channels must have same AREF. */
- if (aref != prev_aref)
- errors |= aref_err;
-
- /* Channel ranges must have same polarity. */
- if (polarity != prev_polarity)
- errors |= polarity_err;
-
- /* Single-ended channel pairs must have same
- * range. */
- if ((aref != AREF_DIFF)
- && (((chan ^ prev_chan) & ~1) == 0)
- && (range != prev_range)) {
- errors |= rangepair_err;
- }
- }
- prev_chan = chan;
- prev_range = range;
- prev_aref = aref;
- prev_polarity = polarity;
- }
- if (subseq_len == 0) {
- /* Subsequence is whole sequence. */
- subseq_len = n;
- }
- /* If channel list is a repeating subsequence, need a whole
- * number of repeats. */
- if ((n % subseq_len) != 0)
- errors |= seq_err;
-
- if ((devpriv->hwver > 0) && (devpriv->hwver < 4)) {
- /*
- * Buggy PCI230+ or PCI260+ requires channel 0 to be
- * (first) in the sequence if the sequence contains
- * more than one channel. Hardware versions 1 and 2
- * have the bug. There is no hardware version 3.
- *
- * Actually, there are two firmwares that report
- * themselves as hardware version 1 (the boards
- * have different ADC chips with slightly different
- * timing requirements, which was supposed to be
- * invisible to software). The first one doesn't
- * seem to have the bug, but the second one
- * does, and we can't tell them apart!
- */
- if ((subseq_len > 1)
- && (CR_CHAN(cmd->chanlist[0]) != 0)) {
- errors |= buggy_chan0_err;
- }
- }
- if (errors != 0) {
- err++;
- if ((errors & seq_err) != 0) {
- DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
- "channel numbers must increase or "
- "sequence must repeat exactly\n",
- dev->minor);
- }
- if ((errors & rangepair_err) != 0) {
- DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
- "single-ended channel pairs must "
- "have the same range\n", dev->minor);
- }
- if ((errors & polarity_err) != 0) {
- DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
- "channel sequence ranges must be all "
- "bipolar or all unipolar\n",
- dev->minor);
- }
- if ((errors & aref_err) != 0) {
- DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
- "channel sequence analogue references "
- "must be all the same (single-ended "
- "or differential)\n", dev->minor);
- }
- if ((errors & diffchan_err) != 0) {
- DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: "
- "differential channel number out of "
- "range 0 to %u\n", dev->minor,
- (s->n_chan / 2) - 1);
- }
- if ((errors & buggy_chan0_err) != 0) {
- dev_info(dev->class_dev,
- "amplc_pci230: ai_cmdtest: Buggy PCI230+/260+ h/w version %u requires first channel of multi-channel sequence to be 0 (corrected in h/w version 4)\n",
- devpriv->hwver);
- }
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= pci230_ai_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -1891,9 +1848,9 @@ static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev,
/* Wake at end of scan. */
wake = scanlen - devpriv->ai_scan_pos;
} else {
- if (devpriv->ai_continuous
- || (devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL)
- || (scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL)) {
+ if (cmd->stop_src != TRIG_COUNT ||
+ devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL ||
+ scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL) {
wake = PCI230_ADC_FIFOLEVEL_HALFFULL;
} else {
wake = (devpriv->ai_scan_count * scanlen)
@@ -2044,7 +2001,7 @@ static void pci230_ai_start(struct comedi_device *dev,
struct comedi_cmd *cmd = &async->cmd;
set_bit(AI_CMD_STARTED, &devpriv->state);
- if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) {
+ if (cmd->stop_src == TRIG_COUNT && devpriv->ai_scan_count == 0) {
/* An empty acquisition! */
async->events |= COMEDI_CB_EOA;
pci230_ai_stop(dev, s);
@@ -2177,7 +2134,9 @@ static int pci230_ai_inttrig_start(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int trig_num)
{
- if (trig_num != 0)
+ struct comedi_cmd *cmd = &s->async->cmd;
+
+ if (trig_num != cmd->start_arg)
return -EINVAL;
s->async->inttrig = NULL;
@@ -2190,16 +2149,17 @@ static void pci230_handle_ai(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct pci230_private *devpriv = dev->private;
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ unsigned int scanlen = cmd->scan_end_arg;
unsigned int events = 0;
unsigned int status_fifo;
unsigned int i;
unsigned int todo;
unsigned int fifoamount;
- struct comedi_async *async = s->async;
- unsigned int scanlen = async->cmd.scan_end_arg;
/* Determine number of samples to read. */
- if (devpriv->ai_continuous) {
+ if (cmd->stop_src != TRIG_COUNT) {
todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
} else if (devpriv->ai_scan_count == 0) {
todo = 0;
@@ -2247,7 +2207,7 @@ static void pci230_handle_ai(struct comedi_device *dev,
}
}
/* Read sample and store in Comedi's circular buffer. */
- if (comedi_buf_put(async, pci230_ai_read(dev)) == 0) {
+ if (comedi_buf_put(s, pci230_ai_read(dev)) == 0) {
events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
comedi_error(dev, "AI buffer overflow");
break;
@@ -2261,7 +2221,7 @@ static void pci230_handle_ai(struct comedi_device *dev,
async->events |= COMEDI_CB_EOS;
}
}
- if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) {
+ if (cmd->stop_src == TRIG_COUNT && devpriv->ai_scan_count == 0) {
/* End of acquisition. */
events |= COMEDI_CB_EOA;
} else {
@@ -2312,14 +2272,10 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* Get number of scans required. */
- if (cmd->stop_src == TRIG_COUNT) {
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->ai_scan_count = cmd->stop_arg;
- devpriv->ai_continuous = 0;
- } else {
- /* TRIG_NONE, user calls cancel. */
+ else /* TRIG_NONE, user calls cancel */
devpriv->ai_scan_count = 0;
- devpriv->ai_continuous = 1;
- }
devpriv->ai_scan_pos = 0; /* Position within scan. */
/* Steps;
@@ -2463,12 +2419,10 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
}
- if (cmd->start_src == TRIG_INT) {
+ if (cmd->start_src == TRIG_INT)
s->async->inttrig = pci230_ai_inttrig_start;
- } else {
- /* TRIG_NOW */
+ else /* TRIG_NOW */
pci230_ai_start(dev, s);
- }
return 0;
}
@@ -2637,7 +2591,7 @@ static int pci230_attach_common(struct comedi_device *dev,
struct comedi_subdevice *s;
unsigned long iobase1, iobase2;
/* PCI230's I/O spaces 1 and 2 respectively. */
- int irq_hdl, rc;
+ int rc;
comedi_set_hw_dev(dev, &pci_dev->dev);
@@ -2709,16 +2663,12 @@ static int pci230_attach_common(struct comedi_device *dev,
outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
dev->iobase + PCI230_ADCCON);
- /* Register the interrupt handler. */
- irq_hdl = request_irq(pci_dev->irq, pci230_interrupt,
- IRQF_SHARED, "amplc_pci230", dev);
- if (irq_hdl < 0) {
- dev_warn(dev->class_dev,
- "unable to register irq %u, commands will not be available\n",
- pci_dev->irq);
- } else {
- dev->irq = pci_dev->irq;
- dev_dbg(dev->class_dev, "registered irq %u\n", pci_dev->irq);
+
+ if (pci_dev->irq) {
+ rc = request_irq(pci_dev->irq, pci230_interrupt, IRQF_SHARED,
+ dev->board_name, dev);
+ if (rc == 0)
+ dev->irq = pci_dev->irq;
}
rc = comedi_alloc_subdevices(dev, 3);
@@ -2734,14 +2684,14 @@ static int pci230_attach_common(struct comedi_device *dev,
s->range_table = &pci230_ai_range;
s->insn_read = &pci230_ai_rinsn;
s->len_chanlist = 256; /* but there are restrictions. */
- /* Only register commands if the interrupt handler is installed. */
- if (irq_hdl == 0) {
+ if (dev->irq) {
dev->read_subdev = s;
s->subdev_flags |= SDF_CMD_READ;
s->do_cmd = &pci230_ai_cmd;
s->do_cmdtest = &pci230_ai_cmdtest;
s->cancel = pci230_ai_cancel;
}
+
s = &dev->subdevices[1];
/* analog output subdevice */
if (thisboard->ao_chans > 0) {
@@ -2753,9 +2703,7 @@ static int pci230_attach_common(struct comedi_device *dev,
s->insn_write = &pci230_ao_winsn;
s->insn_read = &pci230_ao_rinsn;
s->len_chanlist = thisboard->ao_chans;
- /* Only register commands if the interrupt handler is
- * installed. */
- if (irq_hdl == 0) {
+ if (dev->irq) {
dev->write_subdev = s;
s->subdev_flags |= SDF_CMD_WRITE;
s->do_cmd = &pci230_ao_cmd;
@@ -2765,18 +2713,19 @@ static int pci230_attach_common(struct comedi_device *dev,
} else {
s->type = COMEDI_SUBD_UNUSED;
}
+
s = &dev->subdevices[2];
/* digital i/o subdevice */
if (thisboard->have_dio) {
rc = subdev_8255_init(dev, s, NULL,
- (devpriv->iobase1 + PCI230_PPI_X_BASE));
- if (rc < 0)
+ devpriv->iobase1 + PCI230_PPI_X_BASE);
+ if (rc)
return rc;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
- dev_info(dev->class_dev, "attached\n");
- return 1;
+
+ return 0;
}
static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -2856,7 +2805,7 @@ static int amplc_pci230_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(amplc_pci230_pci_table) = {
+static const struct pci_device_id amplc_pci230_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) },
{ 0 }
diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c
index 4bd4ef8e88c..93ed03ee416 100644
--- a/drivers/staging/comedi/drivers/amplc_pci263.c
+++ b/drivers/staging/comedi/drivers/amplc_pci263.c
@@ -84,8 +84,6 @@ static int pci263_auto_attach(struct comedi_device *dev,
/* read initial relay state */
s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8);
- dev_info(dev->class_dev, "%s (pci %s) attached\n", dev->board_name,
- pci_name(pci_dev));
return 0;
}
@@ -96,7 +94,7 @@ static struct comedi_driver amplc_pci263_driver = {
.detach = comedi_pci_disable,
};
-static DEFINE_PCI_DEVICE_TABLE(pci263_pci_table) = {
+static const struct pci_device_id pci263_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) },
{0}
};
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index 217aa19cdc3..e03dd6e7141 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -1,34 +1,33 @@
/*
- comedi/drivers/c6xdigio.c
-
- Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card.
- (http://robot0.ge.uiuc.edu/~spong/mecha/)
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1999 Dan Block
-
- 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.
+ * c6xdigio.c
+ * Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card.
+ * http://web.archive.org/web/%2A/http://robot0.ge.uiuc.edu/~spong/mecha/
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1999 Dan Block
+ *
+ * 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: c6xdigio
-Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card
-Author: Dan Block
-Status: unknown
-Devices: [Mechatronic Systems Inc.] C6x_DIGIO DSP daughter card (c6xdigio)
-Updated: Sun Nov 20 20:18:34 EST 2005
-
-This driver will not work with a 2.4 kernel.
-http://robot0.ge.uiuc.edu/~spong/mecha/
-*/
+/*
+ * Driver: c6xdigio
+ * Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card
+ * Author: Dan Block
+ * Status: unknown
+ * Devices: (Mechatronic Systems Inc.) C6x_DIGIO DSP daughter card [c6xdigio]
+ * Updated: Sun Nov 20 20:18:34 EST 2005
+ *
+ * Configuration Options:
+ * [0] - base address
+ */
#include <linux/kernel.h>
#include <linux/module.h>
@@ -43,351 +42,194 @@ http://robot0.ge.uiuc.edu/~spong/mecha/
#include "../comedidev.h"
-static u8 ReadByteFromHwPort(unsigned long addr)
-{
- u8 result = inb(addr);
- return result;
-}
-
-static void WriteByteToHwPort(unsigned long addr, u8 val)
-{
- outb_p(val, addr);
-}
-
-#define C6XDIGIO_SIZE 3
-
/*
- * port offsets
+ * Register I/O map
*/
-#define C6XDIGIO_PARALLEL_DATA 0
-#define C6XDIGIO_PARALLEL_STATUS 1
-#define C6XDIGIO_PARALLEL_CONTROL 2
-struct pwmbitstype {
- unsigned sb0:2;
- unsigned sb1:2;
- unsigned sb2:2;
- unsigned sb3:2;
- unsigned sb4:2;
-};
-union pwmcmdtype {
- unsigned cmd; /* assuming here that int is 32bit */
- struct pwmbitstype bits;
-};
-struct encbitstype {
- unsigned sb0:3;
- unsigned sb1:3;
- unsigned sb2:3;
- unsigned sb3:3;
- unsigned sb4:3;
- unsigned sb5:3;
- unsigned sb6:3;
- unsigned sb7:3;
-};
-union encvaluetype {
- unsigned value;
- struct encbitstype bits;
-};
+#define C6XDIGIO_DATA_REG 0x00
+#define C6XDIGIO_DATA_CHAN(x) (((x) + 1) << 4)
+#define C6XDIGIO_DATA_PWM (1 << 5)
+#define C6XDIGIO_DATA_ENCODER (1 << 6)
+#define C6XDIGIO_STATUS_REG 0x01
+#define C6XDIGIO_CTRL_REG 0x02
#define C6XDIGIO_TIME_OUT 20
-static void C6X_pwmInit(unsigned long baseAddr)
+static int c6xdigio_chk_status(struct comedi_device *dev, unsigned long context)
{
+ unsigned int status;
int timeout = 0;
-/* printk("Inside C6X_pwmInit\n"); */
-
- WriteByteToHwPort(baseAddr, 0x70);
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
-
- WriteByteToHwPort(baseAddr, 0x74);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
-
- WriteByteToHwPort(baseAddr, 0x70);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0)
- && (timeout < C6XDIGIO_TIME_OUT)) {
+ do {
+ status = inb(dev->iobase + C6XDIGIO_STATUS_REG);
+ if ((status & 0x80) != context)
+ return 0;
timeout++;
- }
-
- WriteByteToHwPort(baseAddr, 0x0);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
+ } while (timeout < C6XDIGIO_TIME_OUT);
+ return -EBUSY;
}
-static void C6X_pwmOutput(unsigned long baseAddr, unsigned channel, int value)
+static int c6xdigio_write_data(struct comedi_device *dev,
+ unsigned int val, unsigned int status)
{
- unsigned ppcmd;
- union pwmcmdtype pwm;
- int timeout = 0;
- unsigned tmp;
-
- /* printk("Inside C6X_pwmOutput\n"); */
-
- pwm.cmd = value;
- if (pwm.cmd > 498)
- pwm.cmd = 498;
- if (pwm.cmd < 2)
- pwm.cmd = 2;
-
- if (channel == 0) {
- ppcmd = 0x28;
- } else { /* if channel == 1 */
- ppcmd = 0x30;
- } /* endif */
-
- WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb0);
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
-
- WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb1 + 0x4);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ outb_p(val, dev->iobase + C6XDIGIO_DATA_REG);
+ return c6xdigio_chk_status(dev, status);
+}
- WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb2);
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+static int c6xdigio_get_encoder_bits(struct comedi_device *dev,
+ unsigned int *bits,
+ unsigned int cmd,
+ unsigned int status)
+{
+ unsigned int val;
- WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb3 + 0x4);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ val = inb(dev->iobase + C6XDIGIO_STATUS_REG);
+ val >>= 3;
+ val &= 0x07;
- WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb4);
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ *bits = val;
- WriteByteToHwPort(baseAddr, 0x0);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ return c6xdigio_write_data(dev, cmd, status);
+}
+static void c6xdigio_pwm_write(struct comedi_device *dev,
+ unsigned int chan, unsigned int val)
+{
+ unsigned int cmd = C6XDIGIO_DATA_PWM | C6XDIGIO_DATA_CHAN(chan);
+ unsigned int bits;
+
+ if (val > 498)
+ val = 498;
+ if (val < 2)
+ val = 2;
+
+ bits = (val >> 0) & 0x03;
+ c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00);
+ bits = (val >> 2) & 0x03;
+ c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80);
+ bits = (val >> 4) & 0x03;
+ c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00);
+ bits = (val >> 6) & 0x03;
+ c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80);
+ bits = (val >> 8) & 0x03;
+ c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00);
+
+ c6xdigio_write_data(dev, 0x00, 0x80);
}
-static int C6X_encInput(unsigned long baseAddr, unsigned channel)
+static int c6xdigio_encoder_read(struct comedi_device *dev,
+ unsigned int chan)
{
- unsigned ppcmd;
- union encvaluetype enc;
- int timeout = 0;
- int tmp;
+ unsigned int cmd = C6XDIGIO_DATA_ENCODER | C6XDIGIO_DATA_CHAN(chan);
+ unsigned int val = 0;
+ unsigned int bits;
- /* printk("Inside C6X_encInput\n"); */
+ c6xdigio_write_data(dev, cmd, 0x00);
- enc.value = 0;
- if (channel == 0)
- ppcmd = 0x48;
- else
- ppcmd = 0x50;
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80);
+ val |= (bits << 0);
- WriteByteToHwPort(baseAddr, ppcmd);
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
+ val |= (bits << 3);
- enc.bits.sb0 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd + 0x4);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb1 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb2 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd + 0x4);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb3 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb4 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd + 0x4);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb5 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb6 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd + 0x4);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
- enc.bits.sb7 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
- WriteByteToHwPort(baseAddr, ppcmd);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80);
+ val |= (bits << 6);
- WriteByteToHwPort(baseAddr, 0x0);
- timeout = 0;
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
+ val |= (bits << 9);
- return enc.value ^ 0x800000;
-}
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80);
+ val |= (bits << 12);
-static void C6X_encResetAll(unsigned long baseAddr)
-{
- unsigned timeout = 0;
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
+ val |= (bits << 15);
-/* printk("Inside C6X_encResetAll\n"); */
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80);
+ val |= (bits << 18);
- WriteByteToHwPort(baseAddr, 0x68);
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
- WriteByteToHwPort(baseAddr, 0x6C);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
- WriteByteToHwPort(baseAddr, 0x68);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
- WriteByteToHwPort(baseAddr, 0x0);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
-}
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
+ val |= (bits << 21);
-static int c6xdigio_pwmo_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- printk(KERN_DEBUG "c6xdigio_pwmo_insn_read %x\n", insn->n);
- return insn->n;
+ c6xdigio_write_data(dev, 0x00, 0x80);
+
+ return val;
}
-static int c6xdigio_pwmo_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int c6xdigio_pwm_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = (s->state >> (16 * chan)) & 0xffff;
int i;
- int chan = CR_CHAN(insn->chanspec);
- /* printk("c6xdigio_pwmo_insn_write %x\n", insn->n); */
for (i = 0; i < insn->n; i++) {
- C6X_pwmOutput(dev->iobase, chan, data[i]);
- /* devpriv->ao_readback[chan] = data[i]; */
+ val = data[i];
+ c6xdigio_pwm_write(dev, chan, val);
}
- return i;
+
+ /*
+ * There are only 2 PWM channels and they have a maxdata of 500.
+ * Instead of allocating private data to save the values in for
+ * readback this driver just packs the values for the two channels
+ * in the s->state.
+ */
+ s->state &= (0xffff << (16 * chan));
+ s->state |= (val << (16 * chan));
+
+ return insn->n;
}
-/* static int c6xdigio_ei_init_insn_read(struct comedi_device *dev, */
-/* struct comedi_subdevice *s, */
-/* struct comedi_insn *insn, */
-/* unsigned int *data) */
-/* { */
-/* printk("c6xdigio_ei_init_insn_read %x\n", insn->n); */
-/* return insn->n; */
-/* } */
-
-/* static int c6xdigio_ei_init_insn_write(struct comedi_device *dev, */
-/* struct comedi_subdevice *s, */
-/* struct comedi_insn *insn, */
-/* unsigned int *data) */
-/* { */
-/* int i; */
-/* int chan = CR_CHAN(insn->chanspec); */
- /* *//* C6X_encResetAll( dev->iobase ); */
- /* *//* return insn->n; */
-/* } */
-
-static int c6xdigio_ei_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int c6xdigio_pwm_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- /* printk("c6xdigio_ei__insn_read %x\n", insn->n); */
- int n;
- int chan = CR_CHAN(insn->chanspec);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
+ int i;
+
+ val = (s->state >> (16 * chan)) & 0xffff;
- for (n = 0; n < insn->n; n++)
- data[n] = (C6X_encInput(dev->iobase, chan) & 0xffffff);
+ for (i = 0; i < insn->n; i++)
+ data[i] = val;
- return n;
+ return insn->n;
}
-static void board_init(struct comedi_device *dev)
+static int c6xdigio_encoder_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
+ int i;
+
+ for (i = 0; i < insn->n; i++) {
+ val = c6xdigio_encoder_read(dev, chan);
- /* printk("Inside board_init\n"); */
+ /* munge two's complement value to offset binary */
+ data[i] = comedi_offset_munge(s, val);
+ }
- C6X_pwmInit(dev->iobase);
- C6X_encResetAll(dev->iobase);
+ return insn->n;
+}
+static void c6xdigio_init(struct comedi_device *dev)
+{
+ /* Initialize the PWM */
+ c6xdigio_write_data(dev, 0x70, 0x00);
+ c6xdigio_write_data(dev, 0x74, 0x80);
+ c6xdigio_write_data(dev, 0x70, 0x00);
+ c6xdigio_write_data(dev, 0x00, 0x80);
+
+ /* Reset the encoders */
+ c6xdigio_write_data(dev, 0x68, 0x00);
+ c6xdigio_write_data(dev, 0x6c, 0x80);
+ c6xdigio_write_data(dev, 0x68, 0x00);
+ c6xdigio_write_data(dev, 0x00, 0x80);
}
static const struct pnp_device_id c6xdigio_pnp_tbl[] = {
@@ -409,7 +251,7 @@ static int c6xdigio_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- ret = comedi_request_region(dev, it->options[0], C6XDIGIO_SIZE);
+ ret = comedi_request_region(dev, it->options[0], 0x03);
if (ret)
return ret;
@@ -422,39 +264,26 @@ static int c6xdigio_attach(struct comedi_device *dev,
s = &dev->subdevices[0];
/* pwm output subdevice */
- s->type = COMEDI_SUBD_AO; /* Not sure what to put here */
- s->subdev_flags = SDF_WRITEABLE;
- s->n_chan = 2;
- /* s->trig[0] = c6xdigio_pwmo; */
- s->insn_read = c6xdigio_pwmo_insn_read;
- s->insn_write = c6xdigio_pwmo_insn_write;
- s->maxdata = 500;
- s->range_table = &range_bipolar10; /* A suitable lie */
+ s->type = COMEDI_SUBD_PWM;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 2;
+ s->maxdata = 500;
+ s->range_table = &range_unknown;
+ s->insn_write = c6xdigio_pwm_insn_write;
+ s->insn_read = c6xdigio_pwm_insn_read;
s = &dev->subdevices[1];
/* encoder (counter) subdevice */
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
- s->n_chan = 2;
- /* s->trig[0] = c6xdigio_ei; */
- s->insn_read = c6xdigio_ei_insn_read;
- s->maxdata = 0xffffff;
- s->range_table = &range_unknown;
-
- /* s = &dev->subdevices[2]; */
- /* pwm output subdevice */
- /* s->type = COMEDI_SUBD_COUNTER; // Not sure what to put here */
- /* s->subdev_flags = SDF_WRITEABLE; */
- /* s->n_chan = 1; */
- /* s->trig[0] = c6xdigio_ei_init; */
- /* s->insn_read = c6xdigio_ei_init_insn_read; */
- /* s->insn_write = c6xdigio_ei_init_insn_write; */
- /* s->maxdata = 0xFFFF; // Really just a don't care */
- /* s->range_table = &range_unknown; // Not sure what to put here */
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
+ s->n_chan = 2;
+ s->maxdata = 0xffffff;
+ s->range_table = &range_unknown;
+ s->insn_read = c6xdigio_encoder_insn_read;
/* I will call this init anyway but more than likely the DSP board */
/* will not be connected when device driver is loaded. */
- board_init(dev);
+ c6xdigio_init(dev);
return 0;
}
@@ -474,5 +303,5 @@ static struct comedi_driver c6xdigio_driver = {
module_comedi_driver(c6xdigio_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for the C6x_DIGIO DSP daughter card");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index 64d5f291553..eb1b92d72e8 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -95,10 +95,17 @@ static const struct comedi_lrange das16cs_ai_range = {
}
};
-static irqreturn_t das16cs_interrupt(int irq, void *d)
+static int das16cs_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- /* struct comedi_device *dev = d; */
- return IRQ_HANDLED;
+ unsigned int status;
+
+ status = inw(dev->iobase + DAS16CS_MISC1);
+ if (status & 0x0080)
+ return 0;
+ return -EBUSY;
}
static int das16cs_ai_rinsn(struct comedi_device *dev,
@@ -109,8 +116,8 @@ static int das16cs_ai_rinsn(struct comedi_device *dev,
int chan = CR_CHAN(insn->chanspec);
int range = CR_RANGE(insn->chanspec);
int aref = CR_AREF(insn->chanspec);
+ int ret;
int i;
- int to;
outw(chan, dev->iobase + DAS16CS_DIO_MUX);
@@ -138,132 +145,16 @@ static int das16cs_ai_rinsn(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
outw(0, dev->iobase + DAS16CS_ADC_DATA);
-#define TIMEOUT 1000
- for (to = 0; to < TIMEOUT; to++) {
- if (inw(dev->iobase + DAS16CS_MISC1) & 0x0080)
- break;
- }
- if (to == TIMEOUT) {
- dev_dbg(dev->class_dev, "cb_das16_cs: ai timeout\n");
- return -ETIME;
- }
+ ret = comedi_timeout(dev, s, insn, das16cs_ai_eoc, 0);
+ if (ret)
+ return ret;
+
data[i] = inw(dev->iobase + DAS16CS_ADC_DATA);
}
return i;
}
-static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- return -EINVAL;
-}
-
-static int das16cs_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
-{
- int err = 0;
- int tmp;
-
- /* Step 1 : check if triggers are trivially valid */
-
- err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
- err |= cfc_check_trigger_src(&cmd->scan_begin_src,
- TRIG_TIMER | TRIG_EXT);
- err |= cfc_check_trigger_src(&cmd->convert_src,
- TRIG_TIMER | TRIG_EXT);
- err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
- err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
-
- if (err)
- return 1;
-
- /* Step 2a : make sure trigger sources are unique */
-
- err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
- err |= cfc_check_trigger_is_unique(cmd->convert_src);
- err |= cfc_check_trigger_is_unique(cmd->stop_src);
-
- /* Step 2b : and mutually compatible */
-
- if (err)
- return 2;
-
- /* Step 3: check if arguments are trivially valid */
-
- err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
-
-#define MAX_SPEED 10000 /* in nanoseconds */
-#define MIN_SPEED 1000000000 /* in nanoseconds */
-
- if (cmd->scan_begin_src == TRIG_TIMER) {
- err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
- MAX_SPEED);
- err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
- MIN_SPEED);
- } else {
- /* external trigger */
- /* should be level/edge, hi/lo specification here */
- /* should specify multiple external triggers */
- err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9);
- }
- if (cmd->convert_src == TRIG_TIMER) {
- err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
- MAX_SPEED);
- err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
- MIN_SPEED);
- } else {
- /* external trigger */
- /* see above */
- err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 9);
- }
-
- err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
-
- if (cmd->stop_src == TRIG_COUNT)
- err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff);
- else /* TRIG_NONE */
- err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
-
- if (err)
- return 3;
-
- /* step 4: fix up any arguments */
-
- if (cmd->scan_begin_src == TRIG_TIMER) {
- unsigned int div1 = 0, div2 = 0;
-
- tmp = cmd->scan_begin_arg;
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
- &div1, &div2,
- &cmd->scan_begin_arg, cmd->flags);
- if (tmp != cmd->scan_begin_arg)
- err++;
- }
- if (cmd->convert_src == TRIG_TIMER) {
- unsigned int div1 = 0, div2 = 0;
-
- tmp = cmd->convert_arg;
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
- &div1, &div2,
- &cmd->scan_begin_arg, cmd->flags);
- if (tmp != cmd->convert_arg)
- err++;
- if (cmd->scan_begin_src == TRIG_TIMER &&
- cmd->scan_begin_arg <
- cmd->convert_arg * cmd->scan_end_arg) {
- cmd->scan_begin_arg =
- cmd->convert_arg * cmd->scan_end_arg;
- err++;
- }
- }
-
- if (err)
- return 4;
-
- return 0;
-}
-
static int das16cs_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -293,6 +184,7 @@ static int das16cs_ao_winsn(struct comedi_device *dev,
for (bit = 15; bit >= 0; bit--) {
int b = (d >> bit) & 0x1;
+
b <<= 1;
outw(status1 | b | 0x0000, dev->iobase + DAS16CS_MISC1);
udelay(1);
@@ -401,10 +293,6 @@ static int das16cs_auto_attach(struct comedi_device *dev,
dev->iobase = link->resource[0]->start;
link->priv = dev;
- ret = pcmcia_request_irq(link, das16cs_interrupt);
- if (ret)
- return ret;
- dev->irq = link->irq;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
@@ -415,7 +303,6 @@ static int das16cs_auto_attach(struct comedi_device *dev,
return ret;
s = &dev->subdevices[0];
- dev->read_subdev = s;
/* analog input subdevice */
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
@@ -424,8 +311,6 @@ static int das16cs_auto_attach(struct comedi_device *dev,
s->range_table = &das16cs_ai_range;
s->len_chanlist = 16;
s->insn_read = das16cs_ai_rinsn;
- s->do_cmd = das16cs_ai_cmd;
- s->do_cmdtest = das16cs_ai_cmdtest;
s = &dev->subdevices[1];
/* analog output subdevice */
@@ -451,10 +336,6 @@ static int das16cs_auto_attach(struct comedi_device *dev,
s->insn_bits = das16cs_dio_insn_bits;
s->insn_config = das16cs_dio_insn_config;
- dev_info(dev->class_dev, "%s: %s, I/O base=0x%04lx, irq=%u\n",
- dev->driver->driver_name, dev->board_name,
- dev->iobase, dev->irq);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index e72a403db17..7377da1aff7 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -181,43 +181,40 @@ static inline unsigned int DAC_DATA_REG(unsigned int channel)
/* analog input ranges for most boards */
static const struct comedi_lrange cb_pcidas_ranges = {
- 8,
- {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25)
- }
+ 8, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
/* pci-das1001 input ranges */
static const struct comedi_lrange cb_pcidas_alt_ranges = {
- 8,
- {
- BIP_RANGE(10),
- BIP_RANGE(1),
- BIP_RANGE(0.1),
- BIP_RANGE(0.01),
- UNI_RANGE(10),
- UNI_RANGE(1),
- UNI_RANGE(0.1),
- UNI_RANGE(0.01)
- }
+ 8, {
+ BIP_RANGE(10),
+ BIP_RANGE(1),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.01),
+ UNI_RANGE(10),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1),
+ UNI_RANGE(0.01)
+ }
};
/* analog output ranges */
static const struct comedi_lrange cb_pcidas_ao_ranges = {
- 4,
- {
- BIP_RANGE(5),
- BIP_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(10),
- }
+ 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(10)
+ }
};
enum trimpot_model {
@@ -379,6 +376,20 @@ static inline unsigned int cal_enable_bits(struct comedi_device *dev)
return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source);
}
+static int cb_pcidas_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct cb_pcidas_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = inw(devpriv->control_status + ADCMUX_CONT);
+ if (status & EOC)
+ return 0;
+ return -EBUSY;
+}
+
static int cb_pcidas_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -388,7 +399,8 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev,
unsigned int range = CR_RANGE(insn->chanspec);
unsigned int aref = CR_AREF(insn->chanspec);
unsigned int bits;
- int n, i;
+ int ret;
+ int n;
/* enable calibration input if appropriate */
if (insn->chanspec & CR_ALT_SOURCE) {
@@ -418,13 +430,9 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev,
outw(0, devpriv->adc_fifo + ADCDATA);
/* wait for conversion to end */
- /* return -ETIMEDOUT if there is a timeout */
- for (i = 0; i < 10000; i++) {
- if (inw(devpriv->control_status + ADCMUX_CONT) & EOC)
- break;
- }
- if (i == 10000)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, cb_pcidas_ai_eoc, 0);
+ if (ret)
+ return ret;
/* read data */
data[n] = inw(devpriv->adc_fifo + ADCDATA);
@@ -795,6 +803,33 @@ static int trimpot_read_insn(struct comedi_device *dev,
return 1;
}
+static int cb_pcidas_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
+ unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
+ int i;
+
+ for (i = 1; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+ unsigned int range = CR_RANGE(cmd->chanlist[i]);
+
+ if (chan != (chan0 + i) % s->n_chan) {
+ dev_dbg(dev->class_dev,
+ "entries in chanlist must be consecutive channels, counting upwards\n");
+ return -EINVAL;
+ }
+
+ if (range != range0) {
+ dev_dbg(dev->class_dev,
+ "entries in chanlist must all have the same gain\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
@@ -802,8 +837,7 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
const struct cb_pcidas_board *thisboard = comedi_board(dev);
struct cb_pcidas_private *devpriv = dev->private;
int err = 0;
- int tmp;
- int i, gain, start_chan;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -838,9 +872,12 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
if (err)
return 2;
- /* step 3: arguments are trivially compatible */
+ /* Step 3: check if arguments are trivially valid */
switch (cmd->start_src) {
+ case TRIG_NOW:
+ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ break;
case TRIG_EXT:
/* External trigger, only CR_EDGE and CR_INVERT flags allowed */
if ((cmd->start_arg
@@ -854,9 +891,6 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
err |= -EINVAL;
}
break;
- default:
- err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
- break;
}
if (cmd->scan_begin_src == TRIG_TIMER)
@@ -878,45 +912,28 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
+ arg = cmd->scan_begin_arg;
i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
&devpriv->divisor1,
&devpriv->divisor2,
- &cmd->scan_begin_arg, cmd->flags);
- if (tmp != cmd->scan_begin_arg)
- err++;
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
+ arg = cmd->convert_arg;
i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
&devpriv->divisor1,
&devpriv->divisor2,
- &cmd->convert_arg, cmd->flags);
- if (tmp != cmd->convert_arg)
- err++;
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
}
if (err)
return 4;
- /* check channel/gain list against card's limitations */
- if (cmd->chanlist) {
- gain = CR_RANGE(cmd->chanlist[0]);
- start_chan = CR_CHAN(cmd->chanlist[0]);
- for (i = 1; i < cmd->chanlist_len; i++) {
- if (CR_CHAN(cmd->chanlist[i]) !=
- (start_chan + i) % s->n_chan) {
- comedi_error(dev,
- "entries in chanlist must be consecutive channels, counting upwards\n");
- err++;
- }
- if (CR_RANGE(cmd->chanlist[i]) != gain) {
- comedi_error(dev,
- "entries in chanlist must all have the same gain\n");
- err++;
- }
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= cb_pcidas_ai_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -924,20 +941,16 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
return 0;
}
-static void cb_pcidas_load_counters(struct comedi_device *dev, unsigned int *ns,
- int rounding_flags)
+static void cb_pcidas_ai_load_counters(struct comedi_device *dev)
{
struct cb_pcidas_private *devpriv = dev->private;
+ unsigned long timer_base = devpriv->pacer_counter_dio + ADC8254;
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
- &devpriv->divisor1, &devpriv->divisor2,
- ns, rounding_flags);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
- /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
- i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 1,
- devpriv->divisor1, 2);
- i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 2,
- devpriv->divisor2, 2);
+ i8254_write(timer_base, 0, 1, devpriv->divisor1);
+ i8254_write(timer_base, 0, 2, devpriv->divisor2);
}
static int cb_pcidas_ai_cmd(struct comedi_device *dev,
@@ -975,12 +988,8 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev,
outw(bits, devpriv->control_status + ADCMUX_CONT);
/* load counters */
- if (cmd->convert_src == TRIG_TIMER)
- cb_pcidas_load_counters(dev, &cmd->convert_arg,
- cmd->flags & TRIG_ROUND_MASK);
- else if (cmd->scan_begin_src == TRIG_TIMER)
- cb_pcidas_load_counters(dev, &cmd->scan_begin_arg,
- cmd->flags & TRIG_ROUND_MASK);
+ if (cmd->scan_begin_src == TRIG_TIMER || cmd->convert_src == TRIG_TIMER)
+ cb_pcidas_ai_load_counters(dev);
/* set number of conversions */
if (cmd->stop_src == TRIG_COUNT)
@@ -1009,9 +1018,9 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev,
/* set start trigger and burst mode */
bits = 0;
- if (cmd->start_src == TRIG_NOW)
+ if (cmd->start_src == TRIG_NOW) {
bits |= SW_TRIGGER;
- else if (cmd->start_src == TRIG_EXT) {
+ } else { /* TRIG_EXT */
bits |= EXT_TRIGGER | TGEN | XTRCL;
if (thisboard->is_1602) {
if (cmd->start_arg & CR_INVERT)
@@ -1019,9 +1028,6 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev,
if (cmd->start_arg & CR_EDGE)
bits |= TGSEL;
}
- } else {
- comedi_error(dev, "bug!");
- return -1;
}
if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1)
bits |= BURSTE;
@@ -1030,6 +1036,25 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev,
return 0;
}
+static int cb_pcidas_ao_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
+
+ if (cmd->chanlist_len > 1) {
+ unsigned int chan1 = CR_CHAN(cmd->chanlist[1]);
+
+ if (chan0 != 0 || chan1 != 1) {
+ dev_dbg(dev->class_dev,
+ "channels must be ordered channel 0, channel 1 in chanlist\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
@@ -1037,7 +1062,7 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
const struct cb_pcidas_board *thisboard = comedi_board(dev);
struct cb_pcidas_private *devpriv = dev->private;
int err = 0;
- int tmp;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -1080,27 +1105,20 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
+ arg = cmd->scan_begin_arg;
i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
&devpriv->ao_divisor1,
&devpriv->ao_divisor2,
- &cmd->scan_begin_arg, cmd->flags);
- if (tmp != cmd->scan_begin_arg)
- err++;
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
if (err)
return 4;
- /* check channel/gain list against card's limitations */
- if (cmd->chanlist && cmd->chanlist_len > 1) {
- if (CR_CHAN(cmd->chanlist[0]) != 0 ||
- CR_CHAN(cmd->chanlist[1]) != 1) {
- comedi_error(dev,
- "channels must be ordered channel 0, channel 1 in chanlist\n");
- err++;
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= cb_pcidas_ao_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -1140,7 +1158,7 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
struct comedi_cmd *cmd = &s->async->cmd;
unsigned long flags;
- if (trig_num != 0)
+ if (trig_num != cmd->start_arg)
return -EINVAL;
/* load up fifo */
@@ -1175,6 +1193,18 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
return 0;
}
+static void cb_pcidas_ao_load_counters(struct comedi_device *dev)
+{
+ struct cb_pcidas_private *devpriv = dev->private;
+ unsigned long timer_base = devpriv->pacer_counter_dio + DAC8254;
+
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
+
+ i8254_write(timer_base, 0, 1, devpriv->ao_divisor1);
+ i8254_write(timer_base, 0, 2, devpriv->ao_divisor2);
+}
+
static int cb_pcidas_ao_cmd(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -1204,18 +1234,9 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev,
outw(0, devpriv->ao_registers + DACFIFOCLR);
/* load counters */
- if (cmd->scan_begin_src == TRIG_TIMER) {
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
- &devpriv->ao_divisor1,
- &devpriv->ao_divisor2,
- &cmd->scan_begin_arg, cmd->flags);
+ if (cmd->scan_begin_src == TRIG_TIMER)
+ cb_pcidas_ao_load_counters(dev);
- /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
- i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 1,
- devpriv->ao_divisor1, 2);
- i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 2,
- devpriv->ao_divisor2, 2);
- }
/* set number of conversions */
if (cmd->stop_src == TRIG_COUNT)
devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg;
@@ -1272,8 +1293,6 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
unsigned int num_points;
unsigned long flags;
- async->events = 0;
-
if (status & DAEMI) {
/* clear dac empty interrupt latch */
spin_lock_irqsave(&dev->spinlock, flags);
@@ -1285,7 +1304,6 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
(cmd->stop_src == TRIG_COUNT
&& devpriv->ao_count)) {
comedi_error(dev, "dac fifo underflow");
- cb_pcidas_ao_cancel(dev, s);
async->events |= COMEDI_CB_ERROR;
}
async->events |= COMEDI_CB_EOA;
@@ -1303,7 +1321,7 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
num_points * sizeof(short));
num_points = num_bytes / sizeof(short);
- if (async->cmd.stop_src == TRIG_COUNT)
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->ao_count -= num_points;
/* write data to board's fifo */
outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer,
@@ -1315,7 +1333,7 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
spin_unlock_irqrestore(&dev->spinlock, flags);
}
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
@@ -1325,6 +1343,7 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
struct cb_pcidas_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async;
+ struct comedi_cmd *cmd;
int status, s5933_status;
int half_fifo = thisboard->fifo_size / 2;
unsigned int num_samples, i;
@@ -1335,7 +1354,7 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
return IRQ_NONE;
async = s->async;
- async->events = 0;
+ cmd = &async->cmd;
s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR);
@@ -1358,7 +1377,7 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
if (status & ADHFI) {
/* read data */
num_samples = half_fifo;
- if (async->cmd.stop_src == TRIG_COUNT &&
+ if (cmd->stop_src == TRIG_COUNT &&
num_samples > devpriv->count) {
num_samples = devpriv->count;
}
@@ -1367,10 +1386,8 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
cfc_write_array_to_buffer(s, devpriv->ai_buffer,
num_samples * sizeof(short));
devpriv->count -= num_samples;
- if (async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0) {
+ if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0)
async->events |= COMEDI_CB_EOA;
- cb_pcidas_cancel(dev, s);
- }
/* clear half-full interrupt latch */
spin_lock_irqsave(&dev->spinlock, flags);
outw(devpriv->adc_fifo_bits | INT,
@@ -1384,10 +1401,9 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
INT_ADCFIFO)) == 0)
break;
cfc_write_to_buffer(s, inw(devpriv->adc_fifo));
- if (async->cmd.stop_src == TRIG_COUNT &&
+ if (cmd->stop_src == TRIG_COUNT &&
--devpriv->count == 0) {
/* end of acquisition */
- cb_pcidas_cancel(dev, s);
async->events |= COMEDI_CB_EOA;
break;
}
@@ -1414,11 +1430,10 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
outw(devpriv->adc_fifo_bits | LADFUL,
devpriv->control_status + INT_ADCFIFO);
spin_unlock_irqrestore(&dev->spinlock, flags);
- cb_pcidas_cancel(dev, s);
async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
}
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
@@ -1579,9 +1594,6 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
devpriv->s5933_config + AMCC_OP_REG_INTCSR);
- dev_info(dev->class_dev, "%s: %s attached\n",
- dev->driver->driver_name, dev->board_name);
-
return 0;
}
@@ -1614,7 +1626,7 @@ static int cb_pcidas_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = {
+static const struct pci_device_id cb_pcidas_pci_table[] = {
{ PCI_VDEVICE(CB, 0x0001), BOARD_PCIDAS1602_16 },
{ PCI_VDEVICE(CB, 0x000f), BOARD_PCIDAS1200 },
{ PCI_VDEVICE(CB, 0x0010), BOARD_PCIDAS1602_12 },
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index ff5206536be..035c3a17600 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -94,15 +94,6 @@ TODO:
#include "plx9080.h"
#include "comedi_fc.h"
-#undef PCIDAS64_DEBUG /* disable debugging code */
-/* #define PCIDAS64_DEBUG enable debugging code */
-
-#ifdef PCIDAS64_DEBUG
-#define DEBUG_PRINT(format, args...) pr_debug(format, ## args)
-#else
-#define DEBUG_PRINT(format, args...) no_printk(format, ## args)
-#endif
-
#define TIMER_BASE 25 /* 40MHz master clock */
/* 100kHz 'prescaled' clock for slow acquisition,
* maybe I'll support this someday */
@@ -438,91 +429,85 @@ static inline uint8_t attenuate_bit(unsigned int channel)
/* analog input ranges for 64xx boards */
static const struct comedi_lrange ai_ranges_64xx = {
- 8,
- {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25)
- }
+ 8, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
/* analog input ranges for 60xx boards */
static const struct comedi_lrange ai_ranges_60xx = {
- 4,
- {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(0.5),
- BIP_RANGE(0.05),
- }
+ 4, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.05)
+ }
};
/* analog input ranges for 6030, etc boards */
static const struct comedi_lrange ai_ranges_6030 = {
- 14,
- {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2),
- BIP_RANGE(1),
- BIP_RANGE(0.5),
- BIP_RANGE(0.2),
- BIP_RANGE(0.1),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2),
- UNI_RANGE(1),
- UNI_RANGE(0.5),
- UNI_RANGE(0.2),
- UNI_RANGE(0.1),
- }
+ 14, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.2),
+ BIP_RANGE(0.1),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2),
+ UNI_RANGE(1),
+ UNI_RANGE(0.5),
+ UNI_RANGE(0.2),
+ UNI_RANGE(0.1)
+ }
};
/* analog input ranges for 6052, etc boards */
static const struct comedi_lrange ai_ranges_6052 = {
- 15,
- {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1),
- BIP_RANGE(0.5),
- BIP_RANGE(0.25),
- BIP_RANGE(0.1),
- BIP_RANGE(0.05),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2),
- UNI_RANGE(1),
- UNI_RANGE(0.5),
- UNI_RANGE(0.2),
- UNI_RANGE(0.1),
- }
+ 15, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.25),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.05),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2),
+ UNI_RANGE(1),
+ UNI_RANGE(0.5),
+ UNI_RANGE(0.2),
+ UNI_RANGE(0.1)
+ }
};
/* analog input ranges for 4020 board */
static const struct comedi_lrange ai_ranges_4020 = {
- 2,
- {
- BIP_RANGE(5),
- BIP_RANGE(1),
- }
+ 2, {
+ BIP_RANGE(5),
+ BIP_RANGE(1)
+ }
};
/* analog output ranges */
static const struct comedi_lrange ao_ranges_64xx = {
- 4,
- {
- BIP_RANGE(5),
- BIP_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(10),
- }
+ 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(10)
+ }
};
static const int ao_range_code_64xx[] = {
@@ -537,11 +522,10 @@ static const int ao_range_code_60xx[] = {
};
static const struct comedi_lrange ao_ranges_6030 = {
- 2,
- {
- BIP_RANGE(10),
- UNI_RANGE(10),
- }
+ 2, {
+ BIP_RANGE(10),
+ UNI_RANGE(10)
+ }
};
static const int ao_range_code_6030[] = {
@@ -550,11 +534,10 @@ static const int ao_range_code_6030[] = {
};
static const struct comedi_lrange ao_ranges_4020 = {
- 2,
- {
- BIP_RANGE(5),
- BIP_RANGE(10),
- }
+ 2, {
+ BIP_RANGE(5),
+ BIP_RANGE(10)
+ }
};
static const int ao_range_code_4020[] = {
@@ -1252,8 +1235,6 @@ static void disable_ai_interrupts(struct comedi_device *dev)
writew(devpriv->intr_enable_bits,
devpriv->main_iobase + INTR_ENABLE_REG);
spin_unlock_irqrestore(&dev->spinlock, flags);
-
- DEBUG_PRINT("intr enable bits 0x%x\n", devpriv->intr_enable_bits);
}
static void enable_ai_interrupts(struct comedi_device *dev,
@@ -1277,7 +1258,6 @@ static void enable_ai_interrupts(struct comedi_device *dev,
devpriv->intr_enable_bits |= bits;
writew(devpriv->intr_enable_bits,
devpriv->main_iobase + INTR_ENABLE_REG);
- DEBUG_PRINT("intr enable bits 0x%x\n", devpriv->intr_enable_bits);
spin_unlock_irqrestore(&dev->spinlock, flags);
}
@@ -1292,38 +1272,6 @@ static void init_plx9080(struct comedi_device *dev)
devpriv->plx_control_bits =
readl(devpriv->plx9080_iobase + PLX_CONTROL_REG);
- /* plx9080 dump */
- DEBUG_PRINT(" plx interrupt status 0x%x\n",
- readl(plx_iobase + PLX_INTRCS_REG));
- DEBUG_PRINT(" plx id bits 0x%x\n", readl(plx_iobase + PLX_ID_REG));
- DEBUG_PRINT(" plx control reg 0x%x\n", devpriv->plx_control_bits);
- DEBUG_PRINT(" plx mode/arbitration reg 0x%x\n",
- readl(plx_iobase + PLX_MARB_REG));
- DEBUG_PRINT(" plx region0 reg 0x%x\n",
- readl(plx_iobase + PLX_REGION0_REG));
- DEBUG_PRINT(" plx region1 reg 0x%x\n",
- readl(plx_iobase + PLX_REGION1_REG));
-
- DEBUG_PRINT(" plx revision 0x%x\n",
- readl(plx_iobase + PLX_REVISION_REG));
- DEBUG_PRINT(" plx dma channel 0 mode 0x%x\n",
- readl(plx_iobase + PLX_DMA0_MODE_REG));
- DEBUG_PRINT(" plx dma channel 1 mode 0x%x\n",
- readl(plx_iobase + PLX_DMA1_MODE_REG));
- DEBUG_PRINT(" plx dma channel 0 pci address 0x%x\n",
- readl(plx_iobase + PLX_DMA0_PCI_ADDRESS_REG));
- DEBUG_PRINT(" plx dma channel 0 local address 0x%x\n",
- readl(plx_iobase + PLX_DMA0_LOCAL_ADDRESS_REG));
- DEBUG_PRINT(" plx dma channel 0 transfer size 0x%x\n",
- readl(plx_iobase + PLX_DMA0_TRANSFER_SIZE_REG));
- DEBUG_PRINT(" plx dma channel 0 descriptor 0x%x\n",
- readl(plx_iobase + PLX_DMA0_DESCRIPTOR_REG));
- DEBUG_PRINT(" plx dma channel 0 command status 0x%x\n",
- readb(plx_iobase + PLX_DMA0_CS_REG));
- DEBUG_PRINT(" plx dma channel 0 threshold 0x%x\n",
- readl(plx_iobase + PLX_DMA0_THRESHOLD_REG));
- DEBUG_PRINT(" plx bigend 0x%x\n", readl(plx_iobase + PLX_BIGEND_REG));
-
#ifdef __BIG_ENDIAN
bits = BIGEND_DMA0 | BIGEND_DMA1;
#else
@@ -1417,9 +1365,6 @@ static int set_ai_fifo_segment_length(struct comedi_device *dev,
devpriv->ai_fifo_segment_length = num_increments * increment_size;
- DEBUG_PRINT("set hardware fifo segment length to %i\n",
- devpriv->ai_fifo_segment_length);
-
return devpriv->ai_fifo_segment_length;
}
@@ -1441,8 +1386,6 @@ static int set_ai_fifo_size(struct comedi_device *dev, unsigned int num_samples)
num_samples = retval * fifo->num_segments * fifo->sample_packing_ratio;
- DEBUG_PRINT("set hardware fifo size to %i\n", num_samples);
-
return num_samples;
}
@@ -1538,8 +1481,6 @@ static int alloc_and_init_dma_members(struct comedi_device *dev)
if (devpriv->ai_dma_desc == NULL)
return -ENOMEM;
- DEBUG_PRINT("ai dma descriptors start at bus addr 0x%llx\n",
- (unsigned long long)devpriv->ai_dma_desc_bus_addr);
if (ao_cmd_is_supported(thisboard)) {
devpriv->ao_dma_desc =
pci_alloc_consistent(pcidev,
@@ -1548,9 +1489,6 @@ static int alloc_and_init_dma_members(struct comedi_device *dev)
&devpriv->ao_dma_desc_bus_addr);
if (devpriv->ao_dma_desc == NULL)
return -ENOMEM;
-
- DEBUG_PRINT("ao dma descriptors start at bus addr 0x%llx\n",
- (unsigned long long)devpriv->ao_dma_desc_bus_addr);
}
/* initialize dma descriptors */
for (i = 0; i < ai_dma_ring_count(thisboard); i++) {
@@ -1650,8 +1588,6 @@ static void i2c_write_byte(struct comedi_device *dev, uint8_t byte)
uint8_t bit;
unsigned int num_bits = 8;
- DEBUG_PRINT("writing to i2c byte 0x%x\n", byte);
-
for (bit = 1 << (num_bits - 1); bit; bit >>= 1) {
i2c_set_scl(dev, 0);
if ((byte & bit))
@@ -1728,17 +1664,37 @@ static void i2c_write(struct comedi_device *dev, unsigned int address,
i2c_stop(dev);
}
+static int cb_pcidas64_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+ struct pcidas64_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readw(devpriv->main_iobase + HW_STATUS_REG);
+ if (thisboard->layout == LAYOUT_4020) {
+ status = readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG);
+ if (status)
+ return 0;
+ } else {
+ if (pipe_full_bits(status))
+ return 0;
+ }
+ return -EBUSY;
+}
+
static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
const struct pcidas64_board *thisboard = comedi_board(dev);
struct pcidas64_private *devpriv = dev->private;
- unsigned int bits = 0, n, i;
+ unsigned int bits = 0, n;
unsigned int channel, range, aref;
unsigned long flags;
- static const int timeout = 100;
+ int ret;
- DEBUG_PRINT("chanspec 0x%x\n", insn->chanspec);
channel = CR_CHAN(insn->chanspec);
range = CR_RANGE(insn->chanspec);
aref = CR_AREF(insn->chanspec);
@@ -1766,7 +1722,6 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
if (insn->chanspec & CR_ALT_SOURCE) {
unsigned int cal_en_bit;
- DEBUG_PRINT("reading calibration source\n");
if (thisboard->layout == LAYOUT_60XX)
cal_en_bit = CAL_EN_60XX_BIT;
else
@@ -1800,7 +1755,6 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
devpriv->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK;
if (insn->chanspec & CR_ALT_SOURCE) {
- DEBUG_PRINT("reading calibration source\n");
devpriv->i2c_cal_range_bits |=
adc_src_4020_bits(devpriv->calibration_source);
} else { /* select BNC inputs */
@@ -1837,25 +1791,10 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
devpriv->main_iobase + ADC_CONVERT_REG);
/* wait for data */
- for (i = 0; i < timeout; i++) {
- bits = readw(devpriv->main_iobase + HW_STATUS_REG);
- DEBUG_PRINT(" pipe bits 0x%x\n", pipe_full_bits(bits));
- if (thisboard->layout == LAYOUT_4020) {
- if (readw(devpriv->main_iobase +
- ADC_WRITE_PNTR_REG))
- break;
- } else {
- if (pipe_full_bits(bits))
- break;
- }
- udelay(1);
- }
- DEBUG_PRINT(" looped %i times waiting for data\n", i);
- if (i == timeout) {
- comedi_error(dev, " analog input read insn timed out");
- dev_info(dev->class_dev, "status 0x%x\n", bits);
- return -ETIME;
- }
+ ret = comedi_timeout(dev, s, insn, cb_pcidas64_ai_eoc, 0);
+ if (ret)
+ return ret;
+
if (thisboard->layout == LAYOUT_4020)
data[n] = readl(devpriv->dio_counter_iobase +
ADC_FIFO_REG) & 0xffff;
@@ -1884,7 +1823,6 @@ static int ai_config_calibration_source(struct comedi_device *dev,
return -EINVAL;
}
- DEBUG_PRINT("setting calibration source to %i\n", source);
devpriv->calibration_source = source;
return 2;
@@ -2057,14 +1995,52 @@ static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
return;
}
+static int cb_pcidas64_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ const struct pcidas64_board *board = comedi_board(dev);
+ unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
+ int i;
+
+ for (i = 1; i < cmd->chanlist_len; i++) {
+ unsigned int aref = CR_AREF(cmd->chanlist[i]);
+
+ if (aref != aref0) {
+ dev_dbg(dev->class_dev,
+ "all elements in chanlist must use the same analog reference\n");
+ return -EINVAL;
+ }
+ }
+
+ if (board->layout == LAYOUT_4020) {
+ unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
+
+ for (i = 1; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+
+ if (chan != (chan0 + i)) {
+ dev_dbg(dev->class_dev,
+ "chanlist must use consecutive channels\n");
+ return -EINVAL;
+ }
+ }
+ if (cmd->chanlist_len == 3) {
+ dev_dbg(dev->class_dev,
+ "chanlist cannot be 3 channels long, use 1, 2, or 4 channels\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
const struct pcidas64_board *thisboard = comedi_board(dev);
int err = 0;
unsigned int tmp_arg, tmp_arg2;
- int i;
- int aref;
unsigned int triggers;
/* Step 1 : check if triggers are trivially valid */
@@ -2102,15 +2078,24 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER)
err |= -EINVAL;
- if (cmd->stop_src != TRIG_COUNT &&
- cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT)
- err |= -EINVAL;
if (err)
return 2;
/* Step 3: check if arguments are trivially valid */
+ switch (cmd->start_src) {
+ case TRIG_NOW:
+ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ break;
+ case TRIG_EXT:
+ /*
+ * start_arg is the CR_CHAN | CR_INVERT of the
+ * external trigger.
+ */
+ break;
+ }
+
if (cmd->convert_src == TRIG_TIMER) {
if (thisboard->layout == LAYOUT_4020) {
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
@@ -2160,36 +2145,9 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
if (err)
return 4;
- /* make sure user is doesn't change analog reference mid chanlist */
- if (cmd->chanlist) {
- aref = CR_AREF(cmd->chanlist[0]);
- for (i = 1; i < cmd->chanlist_len; i++) {
- if (aref != CR_AREF(cmd->chanlist[i])) {
- comedi_error(dev,
- "all elements in chanlist must use the same analog reference");
- err++;
- break;
- }
- }
- /* check 4020 chanlist */
- if (thisboard->layout == LAYOUT_4020) {
- unsigned int first_channel = CR_CHAN(cmd->chanlist[0]);
- for (i = 1; i < cmd->chanlist_len; i++) {
- if (CR_CHAN(cmd->chanlist[i]) !=
- first_channel + i) {
- comedi_error(dev,
- "chanlist must use consecutive channels");
- err++;
- break;
- }
- }
- if (cmd->chanlist_len == 3) {
- comedi_error(dev,
- "chanlist cannot be 3 channels long, use 1, 2, or 4 channels");
- err++;
- }
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= cb_pcidas64_ai_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -2368,7 +2326,6 @@ static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd)
/* load lower 16 bits of convert interval */
writew(convert_counter & 0xffff,
devpriv->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG);
- DEBUG_PRINT("convert counter 0x%x\n", convert_counter);
/* load upper 8 bits of convert interval */
writew((convert_counter >> 16) & 0xff,
devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG);
@@ -2378,7 +2335,6 @@ static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd)
/* load upper 8 bits of scan delay */
writew((scan_counter >> 16) & 0xff,
devpriv->main_iobase + ADC_DELAY_INTERVAL_UPPER_REG);
- DEBUG_PRINT("scan counter 0x%x\n", scan_counter);
}
static int use_internal_queue_6xxx(const struct comedi_cmd *cmd)
@@ -2469,9 +2425,6 @@ static int setup_channel_queue(struct comedi_device *dev,
writew(bits,
devpriv->main_iobase +
ADC_QUEUE_FIFO_REG);
- DEBUG_PRINT(
- "wrote 0x%x to external channel queue\n",
- bits);
}
/* doing a queue clear is not specified in board docs,
* but required for reliable operation */
@@ -2593,7 +2546,6 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
writew(devpriv->adc_control1_bits,
devpriv->main_iobase + ADC_CONTROL1_REG);
- DEBUG_PRINT("control1 bits 0x%x\n", devpriv->adc_control1_bits);
spin_unlock_irqrestore(&dev->spinlock, flags);
/* clear adc buffer */
@@ -2645,17 +2597,14 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (use_hw_sample_counter(cmd))
bits |= ADC_SAMPLE_COUNTER_EN_BIT;
writew(bits, devpriv->main_iobase + ADC_CONTROL0_REG);
- DEBUG_PRINT("control0 bits 0x%x\n", bits);
devpriv->ai_cmd_running = 1;
spin_unlock_irqrestore(&dev->spinlock, flags);
/* start acquisition */
- if (cmd->start_src == TRIG_NOW) {
+ if (cmd->start_src == TRIG_NOW)
writew(0, devpriv->main_iobase + ADC_START_REG);
- DEBUG_PRINT("soft trig\n");
- }
return 0;
}
@@ -2690,10 +2639,6 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev)
read_segment = adc_upper_read_ptr_code(prepost_bits);
write_segment = adc_upper_write_ptr_code(prepost_bits);
- DEBUG_PRINT(" rd seg %i, wrt seg %i, rd idx %i, wrt idx %i\n",
- read_segment, write_segment, read_index,
- write_index);
-
if (read_segment != write_segment)
num_samples =
devpriv->ai_fifo_segment_length - read_index;
@@ -2715,8 +2660,6 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev)
break;
}
- DEBUG_PRINT(" read %i samples from fifo\n", num_samples);
-
for (i = 0; i < num_samples; i++) {
cfc_write_to_buffer(s,
readw(devpriv->main_iobase +
@@ -2780,6 +2723,7 @@ static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel)
const struct pcidas64_board *thisboard = comedi_board(dev);
struct pcidas64_private *devpriv = dev->private;
struct comedi_async *async = dev->read_subdev->async;
+ struct comedi_cmd *cmd = &async->cmd;
uint32_t next_transfer_addr;
int j;
int num_samples = 0;
@@ -2801,7 +2745,7 @@ static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel)
DMA_BUFFER_SIZE) && j < ai_dma_ring_count(thisboard); j++) {
/* transfer data from dma buffer to comedi buffer */
num_samples = dma_transfer_size(dev);
- if (async->cmd.stop_src == TRIG_COUNT) {
+ if (cmd->stop_src == TRIG_COUNT) {
if (num_samples > devpriv->ai_count)
num_samples = devpriv->ai_count;
devpriv->ai_count -= num_samples;
@@ -2812,11 +2756,6 @@ static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel)
num_samples * sizeof(uint16_t));
devpriv->ai_dma_index = (devpriv->ai_dma_index + 1) %
ai_dma_ring_count(thisboard);
-
- DEBUG_PRINT("next buffer addr 0x%lx\n",
- (unsigned long)devpriv->
- ai_buffer_bus_addr[devpriv->ai_dma_index]);
- DEBUG_PRINT("pci addr reg 0x%x\n", next_transfer_addr);
}
/* XXX check for dma ring buffer overrun
* (use end-of-chain bit to mark last unused buffer) */
@@ -2845,24 +2784,17 @@ static void handle_ai_interrupt(struct comedi_device *dev,
if (plx_status & ICS_DMA1_A) { /* dma chan 1 interrupt */
writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT,
devpriv->plx9080_iobase + PLX_DMA1_CS_REG);
- DEBUG_PRINT("dma1 status 0x%x\n", dma1_status);
if (dma1_status & PLX_DMA_EN_BIT)
drain_dma_buffers(dev, 1);
-
- DEBUG_PRINT(" cleared dma ch1 interrupt\n");
}
spin_unlock_irqrestore(&dev->spinlock, flags);
- if (status & ADC_DONE_BIT)
- DEBUG_PRINT("adc done interrupt\n");
-
/* drain fifo with pio */
if ((status & ADC_DONE_BIT) ||
((cmd->flags & TRIG_WAKE_EOS) &&
(status & ADC_INTR_PENDING_BIT) &&
(thisboard->layout != LAYOUT_4020))) {
- DEBUG_PRINT("pio fifo drain\n");
spin_lock_irqsave(&dev->spinlock, flags);
if (devpriv->ai_cmd_running) {
spin_unlock_irqrestore(&dev->spinlock, flags);
@@ -2947,7 +2879,6 @@ static void restart_ao_dma(struct comedi_device *dev)
dma_desc_bits =
readl(devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG);
dma_desc_bits &= ~PLX_END_OF_CHAIN_BIT;
- DEBUG_PRINT("restarting ao dma, descriptor reg 0x%x\n", dma_desc_bits);
load_first_dma_descriptor(dev, 0, dma_desc_bits);
dma_start_sync(dev, 0);
@@ -2963,11 +2894,7 @@ static unsigned int load_ao_dma_buffer(struct comedi_device *dev,
buffer_index = devpriv->ao_dma_index;
prev_buffer_index = prev_ao_dma_index(dev);
- DEBUG_PRINT("attempting to load ao buffer %i (0x%llx)\n", buffer_index,
- (unsigned long long)devpriv->ao_buffer_bus_addr[
- buffer_index]);
-
- num_bytes = comedi_buf_read_n_available(dev->write_subdev->async);
+ num_bytes = comedi_buf_read_n_available(dev->write_subdev);
if (num_bytes > DMA_BUFFER_SIZE)
num_bytes = DMA_BUFFER_SIZE;
if (cmd->stop_src == TRIG_COUNT && num_bytes > devpriv->ao_count)
@@ -2977,8 +2904,6 @@ static unsigned int load_ao_dma_buffer(struct comedi_device *dev,
if (num_bytes == 0)
return 0;
- DEBUG_PRINT("loading %i bytes\n", num_bytes);
-
num_bytes = cfc_read_array_from_buffer(dev->write_subdev,
devpriv->
ao_buffer[buffer_index],
@@ -3052,14 +2977,12 @@ static void handle_ao_interrupt(struct comedi_device *dev,
writeb(PLX_CLEAR_DMA_INTR_BIT,
devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
spin_unlock_irqrestore(&dev->spinlock, flags);
- DEBUG_PRINT("dma0 status 0x%x\n", dma0_status);
if (dma0_status & PLX_DMA_EN_BIT) {
load_ao_dma(dev, cmd);
/* try to recover from dma end-of-chain event */
if (ao_dma_needs_restart(dev, dma0_status))
restart_ao_dma(dev);
}
- DEBUG_PRINT(" cleared dma ch0 interrupt\n");
} else {
spin_unlock_irqrestore(&dev->spinlock, flags);
}
@@ -3068,12 +2991,6 @@ static void handle_ao_interrupt(struct comedi_device *dev,
async->events |= COMEDI_CB_EOA;
if (ao_stopped_by_error(dev, cmd))
async->events |= COMEDI_CB_ERROR;
- DEBUG_PRINT("plx dma0 desc reg 0x%x\n",
- readl(devpriv->plx9080_iobase +
- PLX_DMA0_DESCRIPTOR_REG));
- DEBUG_PRINT("plx dma0 address reg 0x%x\n",
- readl(devpriv->plx9080_iobase +
- PLX_DMA0_PCI_ADDRESS_REG));
}
cfc_handle_events(dev, s);
}
@@ -3089,15 +3006,12 @@ static irqreturn_t handle_interrupt(int irq, void *d)
plx_status = readl(devpriv->plx9080_iobase + PLX_INTRCS_REG);
status = readw(devpriv->main_iobase + HW_STATUS_REG);
- DEBUG_PRINT("hw status 0x%x, plx status 0x%x\n", status, plx_status);
-
/* an interrupt before all the postconfig stuff gets done could
* cause a NULL dereference if we continue through the
* interrupt handler */
- if (!dev->attached) {
- DEBUG_PRINT("premature interrupt, ignoring\n");
+ if (!dev->attached)
return IRQ_HANDLED;
- }
+
handle_ai_interrupt(dev, status, plx_status);
handle_ao_interrupt(dev, status, plx_status);
@@ -3105,11 +3019,8 @@ static irqreturn_t handle_interrupt(int irq, void *d)
if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */
plx_bits = readl(devpriv->plx9080_iobase + PLX_DBR_OUT_REG);
writel(plx_bits, devpriv->plx9080_iobase + PLX_DBR_OUT_REG);
- DEBUG_PRINT(" cleared local doorbell bits 0x%x\n", plx_bits);
}
- DEBUG_PRINT("exiting handler\n");
-
return IRQ_HANDLED;
}
@@ -3130,7 +3041,6 @@ static int ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
abort_dma(dev, 1);
- DEBUG_PRINT("ai canceled\n");
return 0;
}
@@ -3295,15 +3205,17 @@ static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
return 0;
}
-static inline int external_ai_queue_in_use(struct comedi_device *dev)
+static inline int external_ai_queue_in_use(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
{
const struct pcidas64_board *thisboard = comedi_board(dev);
- if (dev->read_subdev->busy)
+ if (s->busy)
return 0;
if (thisboard->layout == LAYOUT_4020)
return 0;
- else if (use_internal_queue_6xxx(&dev->read_subdev->async->cmd))
+ else if (use_internal_queue_6xxx(cmd))
return 0;
return 1;
}
@@ -3315,7 +3227,7 @@ static int ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd = &s->async->cmd;
int retval;
- if (trig_num != 0)
+ if (trig_num != cmd->start_arg)
return -EINVAL;
retval = prep_ao_dma(dev, cmd);
@@ -3337,7 +3249,7 @@ static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
struct pcidas64_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
- if (external_ai_queue_in_use(dev)) {
+ if (external_ai_queue_in_use(dev, s, cmd)) {
warn_external_queue(dev);
return -EBUSY;
}
@@ -3358,13 +3270,32 @@ static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
+static int cb_pcidas64_ao_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
+ int i;
+
+ for (i = 1; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+
+ if (chan != (chan0 + i)) {
+ dev_dbg(dev->class_dev,
+ "chanlist must use consecutive channels\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
const struct pcidas64_board *thisboard = comedi_board(dev);
int err = 0;
unsigned int tmp_arg;
- int i;
/* Step 1 : check if triggers are trivially valid */
@@ -3396,6 +3327,8 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
/* Step 3: check if arguments are trivially valid */
+ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+
if (cmd->scan_begin_src == TRIG_TIMER) {
err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
thisboard->ao_scan_speed);
@@ -3426,17 +3359,9 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
if (err)
return 4;
- if (cmd->chanlist) {
- unsigned int first_channel = CR_CHAN(cmd->chanlist[0]);
- for (i = 1; i < cmd->chanlist_len; i++) {
- if (CR_CHAN(cmd->chanlist[i]) != first_channel + i) {
- comedi_error(dev,
- "chanlist must use consecutive channels");
- err++;
- break;
- }
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= cb_pcidas64_ao_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -3458,7 +3383,6 @@ static int dio_callback(int dir, int port, int data, unsigned long arg)
void __iomem *iobase = (void __iomem *)arg;
if (dir) {
writeb(data, iobase + port);
- DEBUG_PRINT("wrote 0x%x to port %i\n", data, port);
return 0;
} else {
return readb(iobase + port);
@@ -3936,16 +3860,19 @@ static int setup_subdevices(struct comedi_device *dev)
if (thisboard->has_8255) {
if (thisboard->layout == LAYOUT_4020) {
dio_8255_iobase = devpriv->main_iobase + I8255_4020_REG;
- subdev_8255_init(dev, s, dio_callback_4020,
- (unsigned long)dio_8255_iobase);
+ ret = subdev_8255_init(dev, s, dio_callback_4020,
+ (unsigned long)dio_8255_iobase);
} else {
dio_8255_iobase =
devpriv->dio_counter_iobase + DIO_8255_OFFSET;
- subdev_8255_init(dev, s, dio_callback,
- (unsigned long)dio_8255_iobase);
+ ret = subdev_8255_init(dev, s, dio_callback,
+ (unsigned long)dio_8255_iobase);
}
- } else
+ if (ret)
+ return ret;
+ } else {
s->type = COMEDI_SUBD_UNUSED;
+ }
/* 8 channel dio for 60xx */
s = &dev->subdevices[5];
@@ -4046,11 +3973,6 @@ static int auto_attach(struct comedi_device *dev,
return -ENOMEM;
}
- DEBUG_PRINT(" plx9080 remapped to 0x%p\n", devpriv->plx9080_iobase);
- DEBUG_PRINT(" main remapped to 0x%p\n", devpriv->main_iobase);
- DEBUG_PRINT(" diocounter remapped to 0x%p\n",
- devpriv->dio_counter_iobase);
-
/* figure out what local addresses are */
local_range = readl(devpriv->plx9080_iobase + PLX_LAS0RNG_REG) &
LRNG_MEM_MASK;
@@ -4065,9 +3987,6 @@ static int auto_attach(struct comedi_device *dev,
devpriv->local1_iobase = ((uint32_t)devpriv->dio_counter_phys_iobase &
~local_range) | local_decode;
- DEBUG_PRINT(" local 0 io addr 0x%x\n", devpriv->local0_iobase);
- DEBUG_PRINT(" local 1 io addr 0x%x\n", devpriv->local1_iobase);
-
retval = alloc_and_init_dma_members(dev);
if (retval < 0)
return retval;
@@ -4161,7 +4080,7 @@ static int cb_pcidas64_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(cb_pcidas64_pci_table) = {
+static const struct pci_device_id cb_pcidas64_pci_table[] = {
{ PCI_VDEVICE(CB, 0x001d), BOARD_PCIDAS6402_16 },
{ PCI_VDEVICE(CB, 0x001e), BOARD_PCIDAS6402_12 },
{ PCI_VDEVICE(CB, 0x0035), BOARD_PCIDAS64_M1_16 },
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index 94f11582027..901dc5d1bb7 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -388,8 +388,6 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev,
for (i = 0; i < thisboard->ao_chans; i++)
cb_pcidda_calibrate(dev, i, devpriv->ao_range[i]);
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
@@ -407,7 +405,7 @@ static int cb_pcidda_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = {
+static const struct pci_device_id cb_pcidda_pci_table[] = {
{ PCI_VDEVICE(CB, 0x0020), BOARD_DDA02_12 },
{ PCI_VDEVICE(CB, 0x0021), BOARD_DDA04_12 },
{ PCI_VDEVICE(CB, 0x0022), BOARD_DDA08_12 },
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index 30520d4c16a..50e522e6e69 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -31,7 +31,8 @@ Configuration Options:
Developed from cb_pcidas and skel by Richard Bytheway (mocelet@sucs.org).
Only supports DIO, AO and simple AI in it's present form.
-No interrupts, multi channel or FIFO AI, although the card looks like it could support this.
+No interrupts, multi channel or FIFO AI,
+although the card looks like it could support this.
See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details.
*/
@@ -44,9 +45,6 @@ See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details.
#include "plx9052.h"
#include "8255.h"
-/* #define CBPCIMDAS_DEBUG */
-#undef CBPCIMDAS_DEBUG
-
/* Registers for the PCIM-DAS1602/16 */
/* sizes of io regions (bytes) */
@@ -88,21 +86,31 @@ struct cb_pcimdas_private {
unsigned int ao_readback[2];
};
-/*
- * "instructions" read/write data in "one-shot" or "software-triggered"
- * mode.
- */
+static int cb_pcimdas_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct cb_pcimdas_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = inb(devpriv->BADR3 + 2);
+ if ((status & 0x80) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct cb_pcimdas_private *devpriv = dev->private;
- int n, i;
+ int n;
unsigned int d;
- unsigned int busy;
int chan = CR_CHAN(insn->chanspec);
unsigned short chanlims;
int maxchans;
+ int ret;
/* only support sw initiated reads from a single channel */
@@ -121,8 +129,12 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
d = d & 0xfd;
outb(d, devpriv->BADR3 + 5);
}
- outb(0x01, devpriv->BADR3 + 6); /* set bursting off, conversions on */
- outb(0x00, devpriv->BADR3 + 7); /* set range to 10V. UP/BP is controlled by a switch on the board */
+
+ /* set bursting off, conversions on */
+ outb(0x01, devpriv->BADR3 + 6);
+
+ /* set range to 10V. UP/BP is controlled by a switch on the board */
+ outb(0x00, devpriv->BADR3 + 7);
/*
* write channel limits to multiplexer, set Low (bits 0-3) and
@@ -136,19 +148,11 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
/* trigger conversion */
outw(0, dev->iobase + 0);
-#define TIMEOUT 1000 /* typically takes 5 loops on a lightly loaded Pentium 100MHz, */
- /* this is likely to be 100 loops on a 2GHz machine, so set 1000 as the limit. */
-
/* wait for conversion to end */
- for (i = 0; i < TIMEOUT; i++) {
- busy = inb(devpriv->BADR3 + 2) & 0x80;
- if (!busy)
- break;
- }
- if (i == TIMEOUT) {
- printk("timeout\n");
- return -ETIMEDOUT;
- }
+ ret = comedi_timeout(dev, s, insn, cb_pcimdas_ai_eoc, 0);
+ if (ret)
+ return ret;
+
/* read data */
data[n] = inw(dev->iobase + 0);
}
@@ -222,15 +226,6 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev,
devpriv->BADR3 = pci_resource_start(pcidev, 3);
iobase_8255 = pci_resource_start(pcidev, 4);
-/* Dont support IRQ yet */
-/* get irq */
-/* if(request_irq(pcidev->irq, cb_pcimdas_interrupt, IRQF_SHARED, "cb_pcimdas", dev )) */
-/* { */
-/* printk(" unable to allocate irq %u\n", pcidev->irq); */
-/* return -EINVAL; */
-/* } */
-/* dev->irq = pcidev->irq; */
-
ret = comedi_alloc_subdevices(dev, 3);
if (ret)
return ret;
@@ -260,9 +255,9 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev,
s = &dev->subdevices[2];
/* digital i/o subdevice */
- subdev_8255_init(dev, s, NULL, iobase_8255);
-
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
+ ret = subdev_8255_init(dev, s, NULL, iobase_8255);
+ if (ret)
+ return ret;
return 0;
}
@@ -288,7 +283,7 @@ static int cb_pcimdas_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = {
+static const struct pci_device_id cb_pcimdas_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0056) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index edf17b63096..4a2b200de01 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdda.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdda.c
@@ -187,9 +187,7 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
- return 1;
+ return 0;
}
static struct comedi_driver cb_pcimdda_driver = {
@@ -206,7 +204,7 @@ static int cb_pcimdda_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(cb_pcimdda_pci_table) = {
+static const struct pci_device_id cb_pcimdda_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_ID_PCIM_DDA06_16) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index 51a59e5b8ec..8450c99af8b 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -211,7 +211,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it)
return -EINVAL;
}
- snprintf(file, sizeof(file), "/dev/comedi%u", minor);
+ snprintf(file, sizeof(file), "/dev/comedi%d", minor);
file[sizeof(file) - 1] = 0;
d = comedi_open(file);
@@ -254,6 +254,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it)
if (!devs) {
dev_err(dev->class_dev,
"Could not allocate memory. Out of memory?\n");
+ kfree(bdev);
return -ENOMEM;
}
devpriv->devs = devs;
@@ -263,7 +264,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it)
char buf[20];
int left =
MAX_BOARD_NAME - strlen(devpriv->name) - 1;
- snprintf(buf, sizeof(buf), "%d:%d ",
+ snprintf(buf, sizeof(buf), "%u:%u ",
bdev->minor, bdev->subdev);
buf[sizeof(buf) - 1] = 0;
strncat(devpriv->name, buf, left);
diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c
index 26d9dbcf8bd..c33c3e5680a 100644
--- a/drivers/staging/comedi/drivers/comedi_fc.c
+++ b/drivers/staging/comedi/drivers/comedi_fc.c
@@ -1,34 +1,53 @@
/*
- comedi/drivers/comedi_fc.c
-
- This is a place for code driver writers wish to share between
- two or more drivers. fc is short
- for frank-common.
-
- Author: Frank Mori Hess <fmhess@users.sourceforge.net>
- Copyright (C) 2002 Frank Mori Hess
-
- 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.
-*/
+ * comedi_fc.c
+ * This is a place for code driver writers wish to share between
+ * two or more drivers. fc is short for frank-common.
+ *
+ * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Copyright (C) 2002 Frank Mori Hess
+ *
+ * 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.
+ */
#include <linux/module.h>
#include "../comedidev.h"
#include "comedi_fc.h"
-static void increment_scan_progress(struct comedi_subdevice *subd,
- unsigned int num_bytes)
+unsigned int cfc_bytes_per_scan(struct comedi_subdevice *s)
{
- struct comedi_async *async = subd->async;
- unsigned int scan_length = cfc_bytes_per_scan(subd);
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int num_samples;
+ unsigned int bits_per_sample;
+
+ switch (s->type) {
+ case COMEDI_SUBD_DI:
+ case COMEDI_SUBD_DO:
+ case COMEDI_SUBD_DIO:
+ bits_per_sample = 8 * bytes_per_sample(s);
+ num_samples = (cmd->chanlist_len + bits_per_sample - 1) /
+ bits_per_sample;
+ break;
+ default:
+ num_samples = cmd->chanlist_len;
+ break;
+ }
+ return num_samples * bytes_per_sample(s);
+}
+EXPORT_SYMBOL_GPL(cfc_bytes_per_scan);
+
+void cfc_inc_scan_progress(struct comedi_subdevice *s, unsigned int num_bytes)
+{
+ struct comedi_async *async = s->async;
+ unsigned int scan_length = cfc_bytes_per_scan(s);
async->scan_progress += num_bytes;
if (async->scan_progress >= scan_length) {
@@ -36,80 +55,78 @@ static void increment_scan_progress(struct comedi_subdevice *subd,
async->events |= COMEDI_CB_EOS;
}
}
+EXPORT_SYMBOL_GPL(cfc_inc_scan_progress);
/* Writes an array of data points to comedi's buffer */
-unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd,
+unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *s,
void *data, unsigned int num_bytes)
{
- struct comedi_async *async = subd->async;
+ struct comedi_async *async = s->async;
unsigned int retval;
if (num_bytes == 0)
return 0;
- retval = comedi_buf_write_alloc(async, num_bytes);
+ retval = comedi_buf_write_alloc(s, num_bytes);
if (retval != num_bytes) {
- dev_warn(subd->device->class_dev, "comedi: buffer overrun\n");
+ dev_warn(s->device->class_dev, "buffer overrun\n");
async->events |= COMEDI_CB_OVERFLOW;
return 0;
}
- comedi_buf_memcpy_to(async, 0, data, num_bytes);
- comedi_buf_write_free(async, num_bytes);
- increment_scan_progress(subd, num_bytes);
+ comedi_buf_memcpy_to(s, 0, data, num_bytes);
+ comedi_buf_write_free(s, num_bytes);
+ cfc_inc_scan_progress(s, num_bytes);
async->events |= COMEDI_CB_BLOCK;
return num_bytes;
}
EXPORT_SYMBOL_GPL(cfc_write_array_to_buffer);
-unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd,
+unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *s,
void *data, unsigned int num_bytes)
{
- struct comedi_async *async = subd->async;
-
if (num_bytes == 0)
return 0;
- num_bytes = comedi_buf_read_alloc(async, num_bytes);
- comedi_buf_memcpy_from(async, 0, data, num_bytes);
- comedi_buf_read_free(async, num_bytes);
- increment_scan_progress(subd, num_bytes);
- async->events |= COMEDI_CB_BLOCK;
+ num_bytes = comedi_buf_read_alloc(s, num_bytes);
+ comedi_buf_memcpy_from(s, 0, data, num_bytes);
+ comedi_buf_read_free(s, num_bytes);
+ cfc_inc_scan_progress(s, num_bytes);
+ s->async->events |= COMEDI_CB_BLOCK;
return num_bytes;
}
EXPORT_SYMBOL_GPL(cfc_read_array_from_buffer);
unsigned int cfc_handle_events(struct comedi_device *dev,
- struct comedi_subdevice *subd)
+ struct comedi_subdevice *s)
{
- unsigned int events = subd->async->events;
+ unsigned int events = s->async->events;
if (events == 0)
return events;
if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW))
- subd->cancel(dev, subd);
+ s->cancel(dev, s);
- comedi_event(dev, subd);
+ comedi_event(dev, s);
return events;
}
EXPORT_SYMBOL_GPL(cfc_handle_events);
-MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>");
-MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers");
-MODULE_LICENSE("GPL");
-
static int __init comedi_fc_init_module(void)
{
return 0;
}
+module_init(comedi_fc_init_module);
static void __exit comedi_fc_cleanup_module(void)
{
}
-
-module_init(comedi_fc_init_module);
module_exit(comedi_fc_cleanup_module);
+
+MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>");
+MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_fc.h b/drivers/staging/comedi/drivers/comedi_fc.h
index 8558b07f8df..541b9371d3d 100644
--- a/drivers/staging/comedi/drivers/comedi_fc.h
+++ b/drivers/staging/comedi/drivers/comedi_fc.h
@@ -1,72 +1,52 @@
/*
- comedi_fc.h
-
- This is a place for code driver writers wish to share between
- two or more drivers. These functions are meant to be used only
- by drivers, they are NOT part of the kcomedilib API!
-
- Author: Frank Mori Hess <fmhess@users.sourceforge.net>
- Copyright (C) 2002 Frank Mori Hess
-
- 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.
-*/
+ * comedi_fc.h
+ * This is a place for code driver writers wish to share between
+ * two or more drivers. These functions are meant to be used only
+ * by drivers, they are NOT part of the kcomedilib API!
+ *
+ * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Copyright (C) 2002 Frank Mori Hess
+ *
+ * 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.
+ */
#ifndef _COMEDI_FC_H
#define _COMEDI_FC_H
#include "../comedidev.h"
+unsigned int cfc_bytes_per_scan(struct comedi_subdevice *);
+void cfc_inc_scan_progress(struct comedi_subdevice *, unsigned int num_bytes);
+
/* Writes an array of data points to comedi's buffer */
-extern unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd,
- void *data,
- unsigned int num_bytes);
+unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *,
+ void *data, unsigned int num_bytes);
-static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *subd,
+static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *s,
unsigned short data)
{
- return cfc_write_array_to_buffer(subd, &data, sizeof(data));
+ return cfc_write_array_to_buffer(s, &data, sizeof(data));
};
-static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice
- *subd, unsigned int data)
+static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice *s,
+ unsigned int data)
{
- return cfc_write_array_to_buffer(subd, &data, sizeof(data));
+ return cfc_write_array_to_buffer(s, &data, sizeof(data));
};
-extern unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd,
- void *data,
- unsigned int num_bytes);
+unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *,
+ void *data, unsigned int num_bytes);
-extern unsigned int cfc_handle_events(struct comedi_device *dev,
- struct comedi_subdevice *subd);
-
-static inline unsigned int cfc_bytes_per_scan(struct comedi_subdevice *subd)
-{
- int num_samples;
- int bits_per_sample;
-
- switch (subd->type) {
- case COMEDI_SUBD_DI:
- case COMEDI_SUBD_DO:
- case COMEDI_SUBD_DIO:
- bits_per_sample = 8 * bytes_per_sample(subd);
- num_samples = (subd->async->cmd.chanlist_len +
- bits_per_sample - 1) / bits_per_sample;
- break;
- default:
- num_samples = subd->async->cmd.chanlist_len;
- break;
- }
- return num_samples * bytes_per_sample(subd);
-}
+unsigned int cfc_handle_events(struct comedi_device *,
+ struct comedi_subdevice *);
/**
* cfc_check_trigger_src() - trivially validate a comedi_cmd trigger source
diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c
index 9de81c7712f..a4274869235 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -181,7 +181,7 @@ static int parport_intr_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
- err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
if (err)
@@ -229,7 +229,7 @@ static irqreturn_t parport_interrupt(int irq, void *d)
if (!(ctrl & PARPORT_CTRL_IRQ_ENA))
return IRQ_NONE;
- comedi_buf_put(s->async, 0);
+ comedi_buf_put(s, 0);
s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
comedi_event(dev, s);
@@ -295,6 +295,7 @@ static int parport_attach(struct comedi_device *dev,
s->maxdata = 1;
s->range_table = &range_digital;
s->insn_bits = parport_intr_insn_bits;
+ s->len_chanlist = 1;
s->do_cmdtest = parport_intr_cmdtest;
s->do_cmd = parport_intr_cmd;
s->cancel = parport_intr_cancel;
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c
index 16c07802107..67a09aa6b72 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -74,11 +74,10 @@ static const int nano_per_micro = 1000;
/* fake analog input ranges */
static const struct comedi_lrange waveform_ai_ranges = {
- 2,
- {
- BIP_RANGE(10),
- BIP_RANGE(5),
- }
+ 2, {
+ BIP_RANGE(10),
+ BIP_RANGE(5)
+ }
};
static unsigned short fake_sawtooth(struct comedi_device *dev,
@@ -186,10 +185,10 @@ static void waveform_ai_interrupt(unsigned long arg)
(devpriv->usec_remainder + elapsed_time) / devpriv->scan_period;
devpriv->usec_remainder =
(devpriv->usec_remainder + elapsed_time) % devpriv->scan_period;
- async->events = 0;
if (cmd->stop_src == TRIG_COUNT) {
unsigned int remaining = cmd->stop_arg - devpriv->ai_count;
+
if (num_scans >= remaining) {
/* about to finish */
num_scans = remaining;
@@ -200,6 +199,7 @@ static void waveform_ai_interrupt(unsigned long arg)
for (i = 0; i < num_scans; i++) {
for (j = 0; j < cmd->chanlist_len; j++) {
unsigned short sample;
+
sample = fake_waveform(dev, CR_CHAN(cmd->chanlist[j]),
CR_RANGE(cmd->chanlist[j]),
devpriv->usec_current +
@@ -226,7 +226,7 @@ static int waveform_ai_cmdtest(struct comedi_device *dev,
struct comedi_cmd *cmd)
{
int err = 0;
- int tmp;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -278,22 +278,18 @@ static int waveform_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
+ arg = cmd->scan_begin_arg;
/* round to nearest microsec */
- cmd->scan_begin_arg =
- nano_per_micro * ((tmp +
- (nano_per_micro / 2)) / nano_per_micro);
- if (tmp != cmd->scan_begin_arg)
- err++;
+ arg = nano_per_micro *
+ ((arg + (nano_per_micro / 2)) / nano_per_micro);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
+ arg = cmd->convert_arg;
/* round to nearest microsec */
- cmd->convert_arg =
- nano_per_micro * ((tmp +
- (nano_per_micro / 2)) / nano_per_micro);
- if (tmp != cmd->convert_arg)
- err++;
+ arg = nano_per_micro *
+ ((arg + (nano_per_micro / 2)) / nano_per_micro);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
}
if (err)
@@ -319,12 +315,8 @@ static int waveform_ai_cmd(struct comedi_device *dev,
if (cmd->convert_src == TRIG_NOW)
devpriv->convert_period = 0;
- else if (cmd->convert_src == TRIG_TIMER)
+ else /* TRIG_TIMER */
devpriv->convert_period = cmd->convert_arg / nano_per_micro;
- else {
- comedi_error(dev, "bug setting conversion period");
- return -1;
- }
do_gettimeofday(&devpriv->last);
devpriv->usec_current = devpriv->last.tv_usec % devpriv->usec_period;
@@ -419,11 +411,7 @@ static int waveform_attach(struct comedi_device *dev,
s->n_chan = N_CHANS;
s->maxdata = 0xffff;
s->range_table = &waveform_ai_ranges;
- s->len_chanlist = s->n_chan * 2;
s->insn_write = waveform_ao_insn_write;
- s->do_cmd = NULL;
- s->do_cmdtest = NULL;
- s->cancel = NULL;
/* Our default loopback value is just a 0V flatline */
for (i = 0; i < s->n_chan; i++)
diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c
index 89836c0828d..0a9c32e9db4 100644
--- a/drivers/staging/comedi/drivers/contec_pci_dio.c
+++ b/drivers/staging/comedi/drivers/contec_pci_dio.c
@@ -92,8 +92,6 @@ static int contec_auto_attach(struct comedi_device *dev,
s->range_table = &range_digital;
s->insn_bits = contec_do_insn_bits;
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
@@ -111,7 +109,7 @@ static int contec_pci_dio_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(contec_pci_dio_pci_table) = {
+static const struct pci_device_id contec_pci_dio_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c
new file mode 100644
index 00000000000..df46e0a5bad
--- /dev/null
+++ b/drivers/staging/comedi/drivers/dac02.c
@@ -0,0 +1,172 @@
+/*
+ * dac02.c
+ * Comedi driver for DAC02 compatible boards
+ * Copyright (C) 2014 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *
+ * Based on the poc driver
+ * Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Copyright (C) 2001 David A. Schleef <ds@schleef.org>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1998 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: dac02
+ * Description: Comedi driver for DAC02 compatible boards
+ * Devices: (Keithley Metrabyte) DAC-02 [dac02]
+ * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
+ * Updated: Tue, 11 Mar 2014 11:27:19 -0700
+ * Status: unknown
+ *
+ * Configuration options:
+ * [0] - I/O port base
+ */
+
+#include <linux/module.h>
+
+#include "../comedidev.h"
+
+/*
+ * The output range is selected by jumpering pins on the I/O connector.
+ *
+ * Range Chan # Jumper pins Output
+ * ------------- ------ ------------- -----------------
+ * 0 to 5V 0 21 to 22 24
+ * 1 15 to 16 18
+ * 0 to 10V 0 20 to 22 24
+ * 1 14 to 16 18
+ * +/-5V 0 21 to 22 23
+ * 1 15 to 16 17
+ * +/-10V 0 20 to 22 23
+ * 1 14 to 16 17
+ * 4 to 20mA 0 21 to 22 25
+ * 1 15 to 16 19
+ * AC reference 0 In on pin 22 24 (2-quadrant)
+ * In on pin 22 23 (4-quadrant)
+ * 1 In on pin 16 18 (2-quadrant)
+ * In on pin 16 17 (4-quadrant)
+ */
+static const struct comedi_lrange das02_ao_ranges = {
+ 6, {
+ UNI_RANGE(5),
+ UNI_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ RANGE_mA(4, 20),
+ RANGE_ext(0, 1)
+ }
+};
+
+struct dac02_private {
+ unsigned int ao_readback[2];
+};
+
+/*
+ * Register I/O map
+ */
+#define DAC02_AO_LSB(x) (0x00 + ((x) * 2))
+#define DAC02_AO_MSB(x) (0x01 + ((x) * 2))
+
+static int dac02_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct dac02_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int val;
+ int i;
+
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+
+ devpriv->ao_readback[chan] = val;
+
+ /*
+ * Unipolar outputs are true binary encoding.
+ * Bipolar outputs are complementary offset binary
+ * (that is, 0 = +full scale, maxdata = -full scale).
+ */
+ if (comedi_range_is_bipolar(s, range))
+ val = s->maxdata - val;
+
+ /*
+ * DACs are double-buffered.
+ * Write LSB then MSB to latch output.
+ */
+ outb((val << 4) & 0xf0, dev->iobase + DAC02_AO_LSB(chan));
+ outb((val >> 4) & 0xff, dev->iobase + DAC02_AO_MSB(chan));
+ }
+
+ return insn->n;
+}
+
+static int dac02_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct dac02_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
+
+ return insn->n;
+}
+
+static int dac02_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct dac02_private *devpriv;
+ struct comedi_subdevice *s;
+ int ret;
+
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+ if (!devpriv)
+ return -ENOMEM;
+
+ ret = comedi_request_region(dev, it->options[0], 0x08);
+ if (ret)
+ return ret;
+
+ ret = comedi_alloc_subdevices(dev, 1);
+ if (ret)
+ return ret;
+
+ /* Analog Output subdevice */
+ s = &dev->subdevices[0];
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 2;
+ s->maxdata = 0x0fff;
+ s->range_table = &das02_ao_ranges;
+ s->insn_write = dac02_ao_insn_write;
+ s->insn_read = dac02_ao_insn_read;
+
+ return 0;
+}
+
+static struct comedi_driver dac02_driver = {
+ .driver_name = "dac02",
+ .module = THIS_MODULE,
+ .attach = dac02_attach,
+ .detach = comedi_legacy_detach,
+};
+module_comedi_driver(dac02_driver);
+
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_DESCRIPTION("Comedi driver for DAC02 compatible boards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index de920ccff40..a8f6036ad82 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -333,14 +333,28 @@ static void setup_sampling(struct comedi_device *dev, int chan, int gain)
writeAcqScanListEntry(dev, word3);
}
+static int daqboard2000_ai_status(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct daqboard2000_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readw(devpriv->daq + acqControl);
+ if (status & context)
+ return 0;
+ return -EBUSY;
+}
+
static int daqboard2000_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
struct daqboard2000_private *devpriv = dev->private;
- unsigned int val;
- int gain, chan, timeout;
+ int gain, chan;
+ int ret;
int i;
writew(DAQBOARD2000_AcqResetScanListFifo |
@@ -367,25 +381,24 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev,
/* Enable reading from the scanlist FIFO */
writew(DAQBOARD2000_SeqStartScanList,
devpriv->daq + acqControl);
- for (timeout = 0; timeout < 20; timeout++) {
- val = readw(devpriv->daq + acqControl);
- if (val & DAQBOARD2000_AcqConfigPipeFull)
- break;
- /* udelay(2); */
- }
+
+ ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status,
+ DAQBOARD2000_AcqConfigPipeFull);
+ if (ret)
+ return ret;
+
writew(DAQBOARD2000_AdcPacerEnable, devpriv->daq + acqControl);
- for (timeout = 0; timeout < 20; timeout++) {
- val = readw(devpriv->daq + acqControl);
- if (val & DAQBOARD2000_AcqLogicScanning)
- break;
- /* udelay(2); */
- }
- for (timeout = 0; timeout < 20; timeout++) {
- val = readw(devpriv->daq + acqControl);
- if (val & DAQBOARD2000_AcqResultsFIFOHasValidData)
- break;
- /* udelay(2); */
- }
+
+ ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status,
+ DAQBOARD2000_AcqLogicScanning);
+ if (ret)
+ return ret;
+
+ ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status,
+ DAQBOARD2000_AcqResultsFIFOHasValidData);
+ if (ret)
+ return ret;
+
data[i] = readw(devpriv->daq + acqResultsFIFO);
writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl);
writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl);
@@ -409,6 +422,21 @@ static int daqboard2000_ao_insn_read(struct comedi_device *dev,
return i;
}
+static int daqboard2000_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct daqboard2000_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int status;
+
+ status = readw(devpriv->daq + dacControl);
+ if ((status & ((chan + 1) * 0x0010)) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int daqboard2000_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -416,8 +444,7 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev,
{
struct daqboard2000_private *devpriv = dev->private;
int chan = CR_CHAN(insn->chanspec);
- unsigned int val;
- int timeout;
+ int ret;
int i;
for (i = 0; i < insn->n; i++) {
@@ -431,12 +458,11 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev,
udelay(1000);
#endif
writew(data[i], devpriv->daq + dacSetting(chan));
- for (timeout = 0; timeout < 20; timeout++) {
- val = readw(devpriv->daq + dacControl);
- if ((val & ((chan + 1) * 0x0010)) == 0)
- break;
- /* udelay(2); */
- }
+
+ ret = comedi_timeout(dev, s, insn, daqboard2000_ao_eoc, 0);
+ if (ret)
+ return ret;
+
devpriv->ao_readback[chan] = data[i];
#if 0
/*
@@ -737,9 +763,6 @@ static int daqboard2000_auto_attach(struct comedi_device *dev,
if (result)
return result;
- dev_info(dev->class_dev, "%s: %s attached\n",
- dev->driver->driver_name, dev->board_name);
-
return 0;
}
@@ -772,7 +795,7 @@ static int daqboard2000_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = {
+static const struct pci_device_id daqboard2000_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_IOTECH, 0x0409) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index 15dd33e3e1c..c5e352fb555 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -120,46 +120,49 @@
/* gainlist same as _pgx_ below */
-static const struct comedi_lrange range_das08_pgl = { 9, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25)
- }
+static const struct comedi_lrange range_das08_pgl = {
+ 9, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
-static const struct comedi_lrange range_das08_pgh = { 12, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(1),
- BIP_RANGE(0.5),
- BIP_RANGE(0.1),
- BIP_RANGE(0.05),
- BIP_RANGE(0.01),
- BIP_RANGE(0.005),
- UNI_RANGE(10),
- UNI_RANGE(1),
- UNI_RANGE(0.1),
- UNI_RANGE(0.01),
- }
+static const struct comedi_lrange range_das08_pgh = {
+ 12, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.05),
+ BIP_RANGE(0.01),
+ BIP_RANGE(0.005),
+ UNI_RANGE(10),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1),
+ UNI_RANGE(0.01)
+ }
};
-static const struct comedi_lrange range_das08_pgm = { 9, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(0.5),
- BIP_RANGE(0.05),
- BIP_RANGE(0.01),
- UNI_RANGE(10),
- UNI_RANGE(1),
- UNI_RANGE(0.1),
- UNI_RANGE(0.01)
- }
+static const struct comedi_lrange range_das08_pgm = {
+ 9, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.05),
+ BIP_RANGE(0.01),
+ UNI_RANGE(10),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1),
+ UNI_RANGE(0.01)
+ }
}; /*
cio-das08jr.pdf
@@ -198,17 +201,29 @@ static const int *const das08_gainlists[] = {
das08_pgm_gainlist,
};
-#define TIMEOUT 100000
+static int das08_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + DAS08_STATUS);
+ if ((status & DAS08_EOC) == 0)
+ return 0;
+ return -EBUSY;
+}
static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
const struct das08_board_struct *thisboard = comedi_board(dev);
struct das08_private_struct *devpriv = dev->private;
- int i, n;
+ int n;
int chan;
int range;
int lsb, msb;
+ int ret;
chan = CR_CHAN(insn->chanspec);
range = CR_RANGE(insn->chanspec);
@@ -241,14 +256,10 @@ static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
/* trigger conversion */
outb_p(0, dev->iobase + DAS08_TRIG_12BIT);
- for (i = 0; i < TIMEOUT; i++) {
- if (!(inb(dev->iobase + DAS08_STATUS) & DAS08_EOC))
- break;
- }
- if (i == TIMEOUT) {
- dev_err(dev->class_dev, "timeout\n");
- return -ETIME;
- }
+ ret = comedi_timeout(dev, s, insn, das08_ai_eoc, 0);
+ if (ret)
+ return ret;
+
msb = inb(dev->iobase + DAS08_MSB);
lsb = inb(dev->iobase + DAS08_LSB);
if (thisboard->ai_encoding == das08_encode12) {
@@ -526,9 +537,10 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
s = &dev->subdevices[4];
/* 8255 */
if (thisboard->i8255_offset != 0) {
- subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase +
- thisboard->
- i8255_offset));
+ ret = subdev_8255_init(dev, s, NULL,
+ dev->iobase + thisboard->i8255_offset);
+ if (ret)
+ return ret;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h
index 46a314c5113..18cc170facd 100644
--- a/drivers/staging/comedi/drivers/das08.h
+++ b/drivers/staging/comedi/drivers/das08.h
@@ -40,7 +40,9 @@ struct das08_board_struct {
};
struct das08_private_struct {
- unsigned int do_mux_bits; /* bits for do/mux register on boards without separate do register */
+ unsigned int do_mux_bits; /* bits for do/mux register on boards
+ * without separate do register
+ */
const unsigned int *pg_gainlist;
unsigned int ao_readback[2]; /* assume 2 AO channels */
};
diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/staging/comedi/drivers/das08_pci.c
index 3a6d3725b25..d94af09151b 100644
--- a/drivers/staging/comedi/drivers/das08_pci.c
+++ b/drivers/staging/comedi/drivers/das08_pci.c
@@ -89,7 +89,7 @@ static int das08_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = {
+static const struct pci_device_id das08_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_PCIDAS08) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index a8446ca0411..2feecf199f2 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -600,29 +600,56 @@ static void das16_timer_interrupt(unsigned long arg)
mod_timer(&devpriv->timer, jiffies + timer_period());
}
+static int das16_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
+ unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
+ int i;
+
+ for (i = 1; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+ unsigned int range = CR_RANGE(cmd->chanlist[i]);
+
+ if (chan != ((chan0 + i) % s->n_chan)) {
+ dev_dbg(dev->class_dev,
+ "entries in chanlist must be consecutive channels, counting upwards\n");
+ return -EINVAL;
+ }
+
+ if (range != range0) {
+ dev_dbg(dev->class_dev,
+ "entries in chanlist must all have the same gain\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
const struct das16_board *board = comedi_board(dev);
struct das16_private_struct *devpriv = dev->private;
- int err = 0, tmp;
- int gain, start_chan, i;
- int mask;
+ int err = 0;
+ unsigned int trig_mask;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
- mask = TRIG_FOLLOW;
+ trig_mask = TRIG_FOLLOW;
if (devpriv->can_burst)
- mask |= TRIG_TIMER | TRIG_EXT;
- err |= cfc_check_trigger_src(&cmd->scan_begin_src, mask);
+ trig_mask |= TRIG_TIMER | TRIG_EXT;
+ err |= cfc_check_trigger_src(&cmd->scan_begin_src, trig_mask);
- tmp = cmd->convert_src;
- mask = TRIG_TIMER | TRIG_EXT;
+ trig_mask = TRIG_TIMER | TRIG_EXT;
if (devpriv->can_burst)
- mask |= TRIG_NOW;
- err |= cfc_check_trigger_src(&cmd->convert_src, mask);
+ trig_mask |= TRIG_NOW;
+ err |= cfc_check_trigger_src(&cmd->convert_src, trig_mask);
err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
@@ -673,44 +700,28 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
/* step 4: fix up arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
- unsigned int tmp = cmd->scan_begin_arg;
- /* set divisors, correct timing arguments */
+ arg = cmd->scan_begin_arg;
i8253_cascade_ns_to_timer(devpriv->clockbase,
&devpriv->divisor1,
&devpriv->divisor2,
- &cmd->scan_begin_arg, cmd->flags);
- err += (tmp != cmd->scan_begin_arg);
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
if (cmd->convert_src == TRIG_TIMER) {
- unsigned int tmp = cmd->convert_arg;
- /* set divisors, correct timing arguments */
+ arg = cmd->convert_arg;
i8253_cascade_ns_to_timer(devpriv->clockbase,
&devpriv->divisor1,
&devpriv->divisor2,
- &cmd->convert_arg, cmd->flags);
- err += (tmp != cmd->convert_arg);
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
}
if (err)
return 4;
- /* check channel/gain list against card's limitations */
- if (cmd->chanlist) {
- gain = CR_RANGE(cmd->chanlist[0]);
- start_chan = CR_CHAN(cmd->chanlist[0]);
- for (i = 1; i < cmd->chanlist_len; i++) {
- if (CR_CHAN(cmd->chanlist[i]) !=
- (start_chan + i) % s->n_chan) {
- dev_err(dev->class_dev,
- "entries in chanlist must be consecutive channels, counting upwards\n");
- err++;
- }
- if (CR_RANGE(cmd->chanlist[i]) != gain) {
- dev_err(dev->class_dev,
- "entries in chanlist must all have the same gain\n");
- err++;
- }
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= das16_ai_check_chanlist(dev, s, cmd);
+
if (err)
return 5;
@@ -727,9 +738,10 @@ static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
&devpriv->divisor1, &devpriv->divisor2,
&ns, rounding_flags);
- /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
- i8254_load(timer_base, 0, 1, devpriv->divisor1, 2);
- i8254_load(timer_base, 0, 2, devpriv->divisor2, 2);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
+ i8254_write(timer_base, 0, 1, devpriv->divisor1);
+ i8254_write(timer_base, 0, 2, devpriv->divisor2);
return ns;
}
@@ -750,8 +762,7 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
return -1;
}
- devpriv->adc_byte_count =
- cmd->stop_arg * cmd->chanlist_len * sizeof(uint16_t);
+ devpriv->adc_byte_count = cmd->stop_arg * cfc_bytes_per_scan(s);
if (devpriv->can_burst)
outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV_REG);
@@ -856,18 +867,17 @@ static void das16_ai_munge(struct comedi_device *dev,
}
}
-static int das16_ai_wait_for_conv(struct comedi_device *dev,
- unsigned int timeout)
+static int das16_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
unsigned int status;
- int i;
- for (i = 0; i < timeout; i++) {
- status = inb(dev->iobase + DAS16_STATUS_REG);
- if (!(status & DAS16_STATUS_BUSY))
- return 0;
- }
- return -ETIME;
+ status = inb(dev->iobase + DAS16_STATUS_REG);
+ if ((status & DAS16_STATUS_BUSY) == 0)
+ return 0;
+ return -EBUSY;
}
static int das16_ai_insn_read(struct comedi_device *dev,
@@ -897,7 +907,7 @@ static int das16_ai_insn_read(struct comedi_device *dev,
/* trigger conversion */
outb_p(0, dev->iobase + DAS16_TRIG_REG);
- ret = das16_ai_wait_for_conv(dev, 1000);
+ ret = comedi_timeout(dev, s, insn, das16_ai_eoc, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index fce9acfe808..ec039fbff0f 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -110,18 +110,18 @@ irq can be omitted, although the cmd interface will not work without it.
#define DAS16M1_82C55 0x400
#define DAS16M1_8254_THIRD 0x404
-static const struct comedi_lrange range_das16m1 = { 9,
- {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25),
- BIP_RANGE(10),
- }
+static const struct comedi_lrange range_das16m1 = {
+ 9, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25),
+ BIP_RANGE(10)
+ }
};
struct das16m1_private_struct {
@@ -150,11 +150,40 @@ static void munge_sample_array(unsigned short *array, unsigned int num_elements)
array[i] = munge_sample(array[i]);
}
+static int das16m1_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ int i;
+
+ if (cmd->chanlist_len == 1)
+ return 0;
+
+ if ((cmd->chanlist_len % 2) != 0) {
+ dev_dbg(dev->class_dev,
+ "chanlist must be of even length or length 1\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+
+ if ((i % 2) != (chan % 2)) {
+ dev_dbg(dev->class_dev,
+ "even/odd channels must go have even/odd chanlist indices\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int das16m1_cmd_test(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
struct das16m1_private_struct *devpriv = dev->private;
- unsigned int err = 0, tmp, i;
+ int err = 0;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -203,35 +232,20 @@ static int das16m1_cmd_test(struct comedi_device *dev,
/* step 4: fix up arguments */
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
- /* calculate counter values that give desired timing */
+ arg = cmd->convert_arg;
i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
&devpriv->divisor1,
&devpriv->divisor2,
- &cmd->convert_arg, cmd->flags);
- if (tmp != cmd->convert_arg)
- err++;
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
}
if (err)
return 4;
- /* check chanlist against board's peculiarities */
- if (cmd->chanlist && cmd->chanlist_len > 1) {
- for (i = 0; i < cmd->chanlist_len; i++) {
- /* even/odd channels must go into even/odd queue addresses */
- if ((i % 2) != (CR_CHAN(cmd->chanlist[i]) % 2)) {
- comedi_error(dev, "bad chanlist:\n"
- " even/odd channels must go have even/odd chanlist indices");
- err++;
- }
- }
- if ((cmd->chanlist_len % 2) != 0) {
- comedi_error(dev,
- "chanlist must be of even length or length 1");
- err++;
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= das16m1_ai_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -239,26 +253,16 @@ static int das16m1_cmd_test(struct comedi_device *dev,
return 0;
}
-/* This function takes a time in nanoseconds and sets the *
- * 2 pacer clocks to the closest frequency possible. It also *
- * returns the actual sampling period. */
-static unsigned int das16m1_set_pacer(struct comedi_device *dev,
- unsigned int ns, int rounding_flags)
+static void das16m1_set_pacer(struct comedi_device *dev)
{
struct das16m1_private_struct *devpriv = dev->private;
+ unsigned long timer_base = dev->iobase + DAS16M1_8254_SECOND;
- i8253_cascade_ns_to_timer_2div(I8254_OSC_BASE_10MHZ,
- &devpriv->divisor1,
- &devpriv->divisor2,
- &ns, rounding_flags);
-
- /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
- i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 1, devpriv->divisor1,
- 2);
- i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 2, devpriv->divisor2,
- 2);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
- return ns;
+ i8254_write(timer_base, 0, 1, devpriv->divisor1);
+ i8254_write(timer_base, 0, 2, devpriv->divisor2);
}
static int das16m1_cmd_exec(struct comedi_device *dev,
@@ -267,13 +271,9 @@ static int das16m1_cmd_exec(struct comedi_device *dev,
struct das16m1_private_struct *devpriv = dev->private;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
+ unsigned long timer_base = dev->iobase + DAS16M1_8254_FIRST;
unsigned int byte, i;
- if (dev->irq == 0) {
- comedi_error(dev, "irq required to execute comedi_cmd");
- return -1;
- }
-
/* disable interrupts and internal pacer */
devpriv->control_state &= ~INTE & ~PACER_MASK;
outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
@@ -283,11 +283,11 @@ static int das16m1_cmd_exec(struct comedi_device *dev,
/* Initialize lower half of hardware counter, used to determine how
* many samples are in fifo. Value doesn't actually load into counter
* until counter's next clock (the next a/d conversion) */
- i8254_load(dev->iobase + DAS16M1_8254_FIRST, 0, 1, 0, 2);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ i8254_write(timer_base, 0, 1, 0);
/* remember current reading of counter so we know when counter has
* actually been loaded */
- devpriv->initial_hw_count =
- i8254_read(dev->iobase + DAS16M1_8254_FIRST, 0, 1);
+ devpriv->initial_hw_count = i8254_read(timer_base, 0, 1);
/* setup channel/gain queue */
for (i = 0; i < cmd->chanlist_len; i++) {
outb(i, dev->iobase + DAS16M1_QUEUE_ADDR);
@@ -297,10 +297,14 @@ static int das16m1_cmd_exec(struct comedi_device *dev,
outb(byte, dev->iobase + DAS16M1_QUEUE_DATA);
}
- /* set counter mode and counts */
- cmd->convert_arg =
- das16m1_set_pacer(dev, cmd->convert_arg,
- cmd->flags & TRIG_ROUND_MASK);
+ /* enable interrupts and set internal pacer counter mode and counts */
+ devpriv->control_state &= ~PACER_MASK;
+ if (cmd->convert_src == TRIG_TIMER) {
+ das16m1_set_pacer(dev);
+ devpriv->control_state |= INT_PACER;
+ } else { /* TRIG_EXT */
+ devpriv->control_state |= EXT_PACER;
+ }
/* set control & status register */
byte = 0;
@@ -313,13 +317,6 @@ static int das16m1_cmd_exec(struct comedi_device *dev,
/* clear interrupt bit */
outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
- /* enable interrupts and internal pacer */
- devpriv->control_state &= ~PACER_MASK;
- if (cmd->convert_src == TRIG_TIMER)
- devpriv->control_state |= INT_PACER;
- else
- devpriv->control_state |= EXT_PACER;
-
devpriv->control_state |= INTE;
outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
@@ -336,14 +333,27 @@ static int das16m1_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
+static int das16m1_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + DAS16M1_CS);
+ if (status & IRQDATA)
+ return 0;
+ return -EBUSY;
+}
+
static int das16m1_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct das16m1_private_struct *devpriv = dev->private;
- int i, n;
+ int ret;
+ int n;
int byte;
- const int timeout = 1000;
/* disable interrupts and internal pacer */
devpriv->control_state &= ~INTE & ~PACER_MASK;
@@ -361,14 +371,10 @@ static int das16m1_ai_rinsn(struct comedi_device *dev,
/* trigger conversion */
outb(0, dev->iobase);
- for (i = 0; i < timeout; i++) {
- if (inb(dev->iobase + DAS16M1_CS) & IRQDATA)
- break;
- }
- if (i == timeout) {
- comedi_error(dev, "timeout");
- return -ETIME;
- }
+ ret = comedi_timeout(dev, s, insn, das16m1_ai_eoc, 0);
+ if (ret)
+ return ret;
+
data[n] = munge_sample(inw(dev->iobase));
}
@@ -412,7 +418,6 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status)
s = dev->read_subdev;
async = s->async;
- async->events = 0;
cmd = &async->cmd;
/* figure out how many samples are in fifo */
@@ -445,8 +450,8 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status)
devpriv->adc_count += num_samples;
if (cmd->stop_src == TRIG_COUNT) {
- if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) { /* end of acquisition */
- das16m1_cancel(dev, s);
+ if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) {
+ /* end of acquisition */
async->events |= COMEDI_CB_EOA;
}
}
@@ -454,13 +459,11 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status)
/* this probably won't catch overruns since the card doesn't generate
* overrun interrupts, but we might as well try */
if (status & OVRUN) {
- das16m1_cancel(dev, s);
async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
comedi_error(dev, "fifo overflow");
}
- comedi_event(dev, s);
-
+ cfc_handle_events(dev, s);
}
static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s)
@@ -508,38 +511,26 @@ static irqreturn_t das16m1_interrupt(int irq, void *d)
static int das16m1_irq_bits(unsigned int irq)
{
- int ret;
-
switch (irq) {
case 10:
- ret = 0x0;
- break;
+ return 0x0;
case 11:
- ret = 0x1;
- break;
+ return 0x1;
case 12:
- ret = 0x2;
- break;
+ return 0x2;
case 15:
- ret = 0x3;
- break;
+ return 0x3;
case 2:
- ret = 0x4;
- break;
+ return 0x4;
case 3:
- ret = 0x5;
- break;
+ return 0x5;
case 5:
- ret = 0x6;
- break;
+ return 0x6;
case 7:
- ret = 0x7;
- break;
+ return 0x7;
default:
- return -1;
- break;
+ return 0x0;
}
- return ret << 4;
}
/*
@@ -553,7 +544,6 @@ static int das16m1_attach(struct comedi_device *dev,
struct das16m1_private_struct *devpriv;
struct comedi_subdevice *s;
int ret;
- unsigned int irq;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
@@ -569,24 +559,12 @@ static int das16m1_attach(struct comedi_device *dev,
return ret;
devpriv->extra_iobase = dev->iobase + DAS16M1_82C55;
- /* now for the irq */
- irq = it->options[1];
- /* make sure it is valid */
- if (das16m1_irq_bits(irq) >= 0) {
- ret = request_irq(irq, das16m1_interrupt, 0,
- dev->driver->driver_name, dev);
- if (ret < 0)
- return ret;
- dev->irq = irq;
- printk
- ("irq %u\n", irq);
- } else if (irq == 0) {
- printk
- (", no irq\n");
- } else {
- comedi_error(dev, "invalid irq\n"
- " valid irqs are 2, 3, 5, 7, 10, 11, 12, or 15\n");
- return -EINVAL;
+ /* only irqs 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, and 15 are valid */
+ if ((1 << it->options[1]) & 0xdcfc) {
+ ret = request_irq(it->options[1], das16m1_interrupt, 0,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = it->options[1];
}
ret = comedi_alloc_subdevices(dev, 4);
@@ -594,20 +572,22 @@ static int das16m1_attach(struct comedi_device *dev,
return ret;
s = &dev->subdevices[0];
- dev->read_subdev = s;
/* ai */
s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
+ s->subdev_flags = SDF_READABLE | SDF_DIFF;
s->n_chan = 8;
- s->subdev_flags = SDF_DIFF;
- s->len_chanlist = 256;
s->maxdata = (1 << 12) - 1;
s->range_table = &range_das16m1;
s->insn_read = das16m1_ai_rinsn;
- s->do_cmdtest = das16m1_cmd_test;
- s->do_cmd = das16m1_cmd_exec;
- s->cancel = das16m1_cancel;
- s->poll = das16m1_poll;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = 256;
+ s->do_cmdtest = das16m1_cmd_test;
+ s->do_cmd = das16m1_cmd_exec;
+ s->cancel = das16m1_cancel;
+ s->poll = das16m1_poll;
+ }
s = &dev->subdevices[1];
/* di */
@@ -640,10 +620,7 @@ static int das16m1_attach(struct comedi_device *dev,
outb(0, dev->iobase + DAS16M1_DIO);
/* set the interrupt level */
- if (dev->irq)
- devpriv->control_state = das16m1_irq_bits(dev->irq);
- else
- devpriv->control_state = 0;
+ devpriv->control_state = das16m1_irq_bits(dev->irq) << 4;
outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
return 0;
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index 1880038956d..859519026c4 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -178,31 +178,29 @@ enum {
/* analog input ranges */
static const struct comedi_lrange range_ai_das1801 = {
- 8,
- {
- RANGE(-5, 5),
- RANGE(-1, 1),
- RANGE(-0.1, 0.1),
- RANGE(-0.02, 0.02),
- RANGE(0, 5),
- RANGE(0, 1),
- RANGE(0, 0.1),
- RANGE(0, 0.02),
- }
+ 8, {
+ BIP_RANGE(5),
+ BIP_RANGE(1),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.02),
+ UNI_RANGE(5),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1),
+ UNI_RANGE(0.02)
+ }
};
static const struct comedi_lrange range_ai_das1802 = {
- 8,
- {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-2.5, 2.5),
- RANGE(-1.25, 1.25),
- RANGE(0, 10),
- RANGE(0, 5),
- RANGE(0, 2.5),
- RANGE(0, 1.25),
- }
+ 8, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
struct das1800_board {
@@ -445,10 +443,9 @@ struct das1800_private {
/* analog out range for 'ao' boards */
/*
static const struct comedi_lrange range_ao_2 = {
- 2,
- {
- RANGE(-10, 10),
- RANGE(-5, 5),
+ 2, {
+ BIP_RANGE(10),
+ BIP_RANGE(5)
}
};
*/
@@ -462,7 +459,7 @@ static inline uint16_t munge_bipolar_sample(const struct comedi_device *dev,
return sample;
}
-static void munge_data(struct comedi_device *dev, uint16_t * array,
+static void munge_data(struct comedi_device *dev, uint16_t *array,
unsigned int num_elements)
{
unsigned int i;
@@ -550,7 +547,7 @@ static void das1800_flush_dma_channel(struct comedi_device *dev,
munge_data(dev, buffer, num_samples);
cfc_write_array_to_buffer(s, buffer, num_bytes);
- if (s->async->cmd.stop_src == TRIG_COUNT)
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->count -= num_samples;
return;
@@ -644,12 +641,11 @@ static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
static void das1800_ai_handler(struct comedi_device *dev)
{
struct das1800_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
+ struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
unsigned int status = inb(dev->iobase + DAS1800_STATUS);
- async->events = 0;
/* select adc for base address + 0 */
outb(ADC, dev->iobase + DAS1800_SELECT);
/* dma buffer full */
@@ -668,9 +664,8 @@ static void das1800_ai_handler(struct comedi_device *dev)
/* clear OVF interrupt bit */
outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS);
comedi_error(dev, "DAS1800 FIFO overflow");
- das1800_cancel(dev, s);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
/* stop taking data if appropriate */
@@ -683,16 +678,12 @@ static void das1800_ai_handler(struct comedi_device *dev)
das1800_flush_dma(dev, s);
else
das1800_handle_fifo_not_empty(dev, s);
- das1800_cancel(dev, s); /* disable hardware conversions */
async->events |= COMEDI_CB_EOA;
} else if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) { /* stop_src TRIG_COUNT */
- das1800_cancel(dev, s); /* disable hardware conversions */
async->events |= COMEDI_CB_EOA;
}
- comedi_event(dev, s);
-
- return;
+ cfc_handle_events(dev, s);
}
static int das1800_ai_poll(struct comedi_device *dev,
@@ -740,7 +731,7 @@ static irqreturn_t das1800_interrupt(int irq, void *d)
/* converts requested conversion timing to timing compatible with
* hardware, used only when card is in 'burst mode'
*/
-static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode)
+static unsigned int burst_convert_arg(unsigned int convert_arg, int flags)
{
unsigned int micro_sec;
@@ -749,7 +740,7 @@ static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode)
convert_arg = 64000;
/* the conversion time must be an integral number of microseconds */
- switch (round_mode) {
+ switch (flags & TRIG_ROUND_MASK) {
case TRIG_ROUND_NEAREST:
default:
micro_sec = (convert_arg + 500) / 1000;
@@ -766,6 +757,26 @@ static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode)
return micro_sec * 1000;
}
+static int das1800_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ unsigned int unipolar0 = CR_RANGE(cmd->chanlist[0]) & UNIPOLAR;
+ int i;
+
+ for (i = 1; i < cmd->chanlist_len; i++) {
+ unsigned int unipolar = CR_RANGE(cmd->chanlist[i]) & UNIPOLAR;
+
+ if (unipolar != unipolar0) {
+ dev_dbg(dev->class_dev,
+ "unipolar and bipolar ranges cannot be mixed in the chanlist\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
/* test analog input cmd */
static int das1800_ai_do_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -774,9 +785,7 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev,
const struct das1800_board *thisboard = comedi_board(dev);
struct das1800_private *devpriv = dev->private;
int err = 0;
- unsigned int tmp_arg;
- int i;
- int unipolar;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -834,66 +843,48 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
- if (cmd->convert_src == TRIG_TIMER) {
- /* if we are not in burst mode */
- if (cmd->scan_begin_src == TRIG_FOLLOW) {
- tmp_arg = cmd->convert_arg;
- /* calculate counter values that give desired timing */
+ if (cmd->scan_begin_src == TRIG_FOLLOW &&
+ cmd->convert_src == TRIG_TIMER) {
+ /* we are not in burst mode */
+ arg = cmd->convert_arg;
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ,
+ &devpriv->divisor1,
+ &devpriv->divisor2,
+ &cmd->convert_arg, cmd->flags);
+ if (arg != cmd->convert_arg)
+ err++;
+ } else if (cmd->convert_src == TRIG_TIMER) {
+ /* we are in burst mode */
+ arg = cmd->convert_arg;
+ cmd->convert_arg = burst_convert_arg(cmd->convert_arg,
+ cmd->flags);
+ if (arg != cmd->convert_arg)
+ err++;
+
+ if (cmd->scan_begin_src == TRIG_TIMER) {
+ arg = cmd->convert_arg * cmd->chanlist_len;
+ if (arg > cmd->scan_begin_arg) {
+ cmd->scan_begin_arg = arg;
+ err++;
+ }
+
+ arg = cmd->scan_begin_arg;
i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ,
&devpriv->divisor1,
&devpriv->divisor2,
- &cmd->convert_arg,
+ &cmd->scan_begin_arg,
cmd->flags);
- if (tmp_arg != cmd->convert_arg)
+ if (arg != cmd->scan_begin_arg)
err++;
}
- /* if we are in burst mode */
- else {
- /* check that convert_arg is compatible */
- tmp_arg = cmd->convert_arg;
- cmd->convert_arg =
- burst_convert_arg(cmd->convert_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp_arg != cmd->convert_arg)
- err++;
-
- if (cmd->scan_begin_src == TRIG_TIMER) {
- /* if scans are timed faster than conversion rate allows */
- if (cmd->convert_arg * cmd->chanlist_len >
- cmd->scan_begin_arg) {
- cmd->scan_begin_arg =
- cmd->convert_arg *
- cmd->chanlist_len;
- err++;
- }
- tmp_arg = cmd->scan_begin_arg;
- /* calculate counter values that give desired timing */
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ,
- &devpriv->divisor1,
- &devpriv->divisor2,
- &cmd->scan_begin_arg,
- cmd->flags);
- if (tmp_arg != cmd->scan_begin_arg)
- err++;
- }
- }
}
if (err)
return 4;
- /* make sure user is not trying to mix unipolar and bipolar ranges */
- if (cmd->chanlist) {
- unipolar = CR_RANGE(cmd->chanlist[0]) & UNIPOLAR;
- for (i = 1; i < cmd->chanlist_len; i++) {
- if (unipolar != (CR_RANGE(cmd->chanlist[i]) & UNIPOLAR)) {
- comedi_error(dev,
- "unipolar and bipolar ranges cannot be mixed in the chanlist");
- err++;
- break;
- }
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= das1800_ai_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -971,68 +962,29 @@ static int control_c_bits(const struct comedi_cmd *cmd)
return control_c;
}
-/* loads counters with divisor1, divisor2 from private structure */
-static int das1800_set_frequency(struct comedi_device *dev)
+static void das1800_setup_counters(struct comedi_device *dev,
+ const struct comedi_cmd *cmd)
{
struct das1800_private *devpriv = dev->private;
- int err = 0;
-
- /* counter 1, mode 2 */
- if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 1, devpriv->divisor1,
- 2))
- err++;
- /* counter 2, mode 2 */
- if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 2, devpriv->divisor2,
- 2))
- err++;
- if (err)
- return -1;
+ unsigned long timer_base = dev->iobase + DAS1800_COUNTER;
- return 0;
-}
-
-/* sets up counters */
-static int setup_counters(struct comedi_device *dev,
- const struct comedi_cmd *cmd)
-{
- struct das1800_private *devpriv = dev->private;
- unsigned int period;
+ /* setup cascaded counters for conversion/scan frequency */
+ if ((cmd->scan_begin_src == TRIG_FOLLOW ||
+ cmd->scan_begin_src == TRIG_TIMER) &&
+ cmd->convert_src == TRIG_TIMER) {
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
- /* setup cascaded counters for conversion/scan frequency */
- switch (cmd->scan_begin_src) {
- case TRIG_FOLLOW: /* not in burst mode */
- if (cmd->convert_src == TRIG_TIMER) {
- /* set conversion frequency */
- period = cmd->convert_arg;
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ,
- &devpriv->divisor1,
- &devpriv->divisor2,
- &period, cmd->flags);
- if (das1800_set_frequency(dev) < 0)
- return -1;
- }
- break;
- case TRIG_TIMER: /* in burst mode */
- /* set scan frequency */
- period = cmd->scan_begin_arg;
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ,
- &devpriv->divisor1,
- &devpriv->divisor2,
- &period, cmd->flags);
- if (das1800_set_frequency(dev) < 0)
- return -1;
- break;
- default:
- break;
+ i8254_write(timer_base, 0, 1, devpriv->divisor1);
+ i8254_write(timer_base, 0, 2, devpriv->divisor2);
}
- /* setup counter 0 for 'about triggering' */
+ /* setup counter 0 for 'about triggering' */
if (cmd->stop_src == TRIG_EXT) {
- /* load counter 0 in mode 0 */
- i8254_load(dev->iobase + DAS1800_COUNTER, 0, 0, 1, 0);
- }
+ i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY);
- return 0;
+ i8254_write(timer_base, 0, 0, 1);
+ }
}
/* utility function that suggests a dma transfer size based on the conversion period 'ns' */
@@ -1145,17 +1097,10 @@ static int das1800_ai_do_cmd(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct das1800_private *devpriv = dev->private;
- int ret;
int control_a, control_c;
struct comedi_async *async = s->async;
const struct comedi_cmd *cmd = &async->cmd;
- if (!dev->irq) {
- comedi_error(dev,
- "no irq assigned for das-1800, cannot do hardware conversions");
- return -1;
- }
-
/* disable dma on TRIG_WAKE_EOS, or TRIG_RT
* (because dma in handler is unsafe at hard real-time priority) */
if (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT))
@@ -1182,11 +1127,7 @@ static int das1800_ai_do_cmd(struct comedi_device *dev,
/* setup card and start */
program_chanlist(dev, cmd);
- ret = setup_counters(dev, cmd);
- if (ret < 0) {
- comedi_error(dev, "Error setting up counters");
- return ret;
- }
+ das1800_setup_counters(dev, cmd);
setup_dma(dev, cmd);
outb(control_c, dev->iobase + DAS1800_CONTROL_C);
/* set conversion rate and length for burst mode */
@@ -1485,7 +1426,7 @@ static int das1800_probe(struct comedi_device *dev)
static int das1800_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- const struct das1800_board *thisboard = comedi_board(dev);
+ const struct das1800_board *thisboard;
struct das1800_private *devpriv;
struct comedi_subdevice *s;
unsigned int irq = it->options[1];
@@ -1522,43 +1463,34 @@ static int das1800_attach(struct comedi_device *dev,
devpriv->iobase2 = iobase2;
}
- /* grab our IRQ */
- if (irq) {
- if (request_irq(irq, das1800_interrupt, 0,
- dev->driver->driver_name, dev)) {
- dev_dbg(dev->class_dev, "unable to allocate irq %u\n",
- irq);
- return -EINVAL;
- }
- }
- dev->irq = irq;
+ if (irq == 3 || irq == 5 || irq == 7 || irq == 10 || irq == 11 ||
+ irq == 15) {
+ ret = request_irq(irq, das1800_interrupt, 0,
+ dev->board_name, dev);
+ if (ret == 0) {
+ dev->irq = irq;
- /* set bits that tell card which irq to use */
- switch (irq) {
- case 0:
- break;
- case 3:
- devpriv->irq_dma_bits |= 0x8;
- break;
- case 5:
- devpriv->irq_dma_bits |= 0x10;
- break;
- case 7:
- devpriv->irq_dma_bits |= 0x18;
- break;
- case 10:
- devpriv->irq_dma_bits |= 0x28;
- break;
- case 11:
- devpriv->irq_dma_bits |= 0x30;
- break;
- case 15:
- devpriv->irq_dma_bits |= 0x38;
- break;
- default:
- dev_err(dev->class_dev, "irq out of range\n");
- return -EINVAL;
- break;
+ switch (irq) {
+ case 3:
+ devpriv->irq_dma_bits |= 0x8;
+ break;
+ case 5:
+ devpriv->irq_dma_bits |= 0x10;
+ break;
+ case 7:
+ devpriv->irq_dma_bits |= 0x18;
+ break;
+ case 10:
+ devpriv->irq_dma_bits |= 0x28;
+ break;
+ case 11:
+ devpriv->irq_dma_bits |= 0x30;
+ break;
+ case 15:
+ devpriv->irq_dma_bits |= 0x38;
+ break;
+ }
+ }
}
ret = das1800_init_dma(dev, dma0, dma1);
@@ -1578,20 +1510,23 @@ static int das1800_attach(struct comedi_device *dev,
/* analog input subdevice */
s = &dev->subdevices[0];
- dev->read_subdev = s;
s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND | SDF_CMD_READ;
+ s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND;
if (thisboard->common)
s->subdev_flags |= SDF_COMMON;
s->n_chan = thisboard->qram_len;
- s->len_chanlist = thisboard->qram_len;
s->maxdata = (1 << thisboard->resolution) - 1;
s->range_table = thisboard->range_ai;
- s->do_cmd = das1800_ai_do_cmd;
- s->do_cmdtest = das1800_ai_do_cmdtest;
s->insn_read = das1800_ai_rinsn;
- s->poll = das1800_ai_poll;
- s->cancel = das1800_cancel;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = s->n_chan;
+ s->do_cmd = das1800_ai_do_cmd;
+ s->do_cmdtest = das1800_ai_do_cmdtest;
+ s->poll = das1800_ai_poll;
+ s->cancel = das1800_cancel;
+ }
/* analog out */
s = &dev->subdevices[1];
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index fb25cb84703..d18eea6c01a 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -1,318 +1,532 @@
/*
- Some comments on the code..
-
- - it shouldn't be necessary to use outb_p().
-
- - ignoreirq creates a race condition. It needs to be fixed.
-
+ * das6402.c
+ * Comedi driver for DAS6402 compatible boards
+ * Copyright(c) 2014 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *
+ * Rewrite of an experimental driver by:
+ * Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.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.
*/
/*
- comedi/drivers/das6402.c
- An experimental driver for Computerboards' DAS6402 I/O card
+ * Driver: das6402
+ * Description: Keithley Metrabyte DAS6402 (& compatibles)
+ * Devices: (Keithley Metrabyte) DAS6402-12 (das6402-12)
+ * (Keithley Metrabyte) DAS6402-16 (das6402-16)
+ * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
+ * Updated: Fri, 14 Mar 2014 10:18:43 -0700
+ * Status: unknown
+ *
+ * Configuration Options:
+ * [0] - I/O base address
+ * [1] - IRQ (optional, needed for async command support)
+ */
- Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org>
+#include <linux/module.h>
+#include <linux/interrupt.h>
- 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.
+#include "../comedidev.h"
+#include "8253.h"
- 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: das6402
-Description: Keithley Metrabyte DAS6402 (& compatibles)
-Author: Oystein Svendsen <svendsen@pvv.org>
-Status: bitrotten
-Devices: [Keithley Metrabyte] DAS6402 (das6402)
+ * Register I/O map
+ */
+#define DAS6402_AI_DATA_REG 0x00
+#define DAS6402_AI_MUX_REG 0x02
+#define DAS6402_AI_MUX_LO(x) (((x) & 0x3f) << 0)
+#define DAS6402_AI_MUX_HI(x) (((x) & 0x3f) << 8)
+#define DAS6402_DI_DO_REG 0x03
+#define DAS6402_AO_DATA_REG(x) (0x04 + ((x) * 2))
+#define DAS6402_AO_LSB_REG(x) (0x04 + ((x) * 2))
+#define DAS6402_AO_MSB_REG(x) (0x05 + ((x) * 2))
+#define DAS6402_STATUS_REG 0x08
+#define DAS6402_STATUS_FFNE (1 << 0)
+#define DAS6402_STATUS_FHALF (1 << 1)
+#define DAS6402_STATUS_FFULL (1 << 2)
+#define DAS6402_STATUS_XINT (1 << 3)
+#define DAS6402_STATUS_INT (1 << 4)
+#define DAS6402_STATUS_XTRIG (1 << 5)
+#define DAS6402_STATUS_INDGT (1 << 6)
+#define DAS6402_STATUS_10MHZ (1 << 7)
+#define DAS6402_STATUS_W_CLRINT (1 << 0)
+#define DAS6402_STATUS_W_CLRXTR (1 << 1)
+#define DAS6402_STATUS_W_CLRXIN (1 << 2)
+#define DAS6402_STATUS_W_EXTEND (1 << 4)
+#define DAS6402_STATUS_W_ARMED (1 << 5)
+#define DAS6402_STATUS_W_POSTMODE (1 << 6)
+#define DAS6402_STATUS_W_10MHZ (1 << 7)
+#define DAS6402_CTRL_REG 0x09
+#define DAS6402_CTRL_SOFT_TRIG (0 << 0)
+#define DAS6402_CTRL_EXT_FALL_TRIG (1 << 0)
+#define DAS6402_CTRL_EXT_RISE_TRIG (2 << 0)
+#define DAS6402_CTRL_PACER_TRIG (3 << 0)
+#define DAS6402_CTRL_BURSTEN (1 << 2)
+#define DAS6402_CTRL_XINTE (1 << 3)
+#define DAS6402_CTRL_IRQ(x) ((x) << 4)
+#define DAS6402_CTRL_INTE (1 << 7)
+#define DAS6402_TRIG_REG 0x0a
+#define DAS6402_TRIG_TGEN (1 << 0)
+#define DAS6402_TRIG_TGSEL (1 << 1)
+#define DAS6402_TRIG_TGPOL (1 << 2)
+#define DAS6402_TRIG_PRETRIG (1 << 3)
+#define DAS6402_AO_RANGE(_chan, _range) ((_range) << ((_chan) ? 6 : 4))
+#define DAS6402_AO_RANGE_MASK(_chan) (3 << ((_chan) ? 6 : 4))
+#define DAS6402_MODE_REG 0x0b
+#define DAS6402_MODE_RANGE(x) ((x) << 0)
+#define DAS6402_MODE_POLLED (0 << 2)
+#define DAS6402_MODE_FIFONEPTY (1 << 2)
+#define DAS6402_MODE_FIFOHFULL (2 << 2)
+#define DAS6402_MODE_EOB (3 << 2)
+#define DAS6402_MODE_ENHANCED (1 << 4)
+#define DAS6402_MODE_SE (1 << 5)
+#define DAS6402_MODE_UNI (1 << 6)
+#define DAS6402_MODE_DMA1 (0 << 7)
+#define DAS6402_MODE_DMA3 (1 << 7)
+#define DAS6402_TIMER_BASE 0x0c
+
+static const struct comedi_lrange das6402_ai_ranges = {
+ 8, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
+};
-This driver has suffered bitrot.
-*/
+/*
+ * Analog output ranges are programmable on the DAS6402/12.
+ * For the DAS6402/16 the range bits have no function, the
+ * DAC ranges are selected by switches on the board.
+ */
+static const struct comedi_lrange das6402_ao_ranges = {
+ 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(10)
+ }
+};
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include "../comedidev.h"
+struct das6402_boardinfo {
+ const char *name;
+ unsigned int maxdata;
+};
-#define DAS6402_SIZE 16
-
-#define N_WORDS (3000*64)
-
-#define STOP 0
-#define START 1
-
-#define SCANL 0x3f00
-#define BYTE unsigned char
-#define WORD unsigned short
-
-/*----- register 8 ----*/
-#define CLRINT 0x01
-#define CLRXTR 0x02
-#define CLRXIN 0x04
-#define EXTEND 0x10
-#define ARMED 0x20 /* enable conting of post sample conv */
-#define POSTMODE 0x40
-#define MHZ 0x80 /* 10 MHz clock */
-/*---------------------*/
-
-/*----- register 9 ----*/
-#define IRQ (0x04 << 4) /* these two are */
-#define IRQV 10 /* dependent on each other */
-
-#define CONVSRC 0x03 /* trig src is Intarnal pacer */
-#define BURSTEN 0x04 /* enable burst */
-#define XINTE 0x08 /* use external int. trig */
-#define INTE 0x80 /* enable analog interrupts */
-/*---------------------*/
-
-/*----- register 10 ---*/
-#define TGEN 0x01 /* Use pin DI1 for externl trigging? */
-#define TGSEL 0x02 /* Use edge triggering */
-#define TGPOL 0x04 /* active edge is falling */
-#define PRETRIG 0x08 /* pretrig */
-/*---------------------*/
-
-/*----- register 11 ---*/
-#define EOB 0x0c
-#define FIFOHFULL 0x08
-#define GAIN 0x01
-#define FIFONEPTY 0x04
-#define MODE 0x10
-#define SEM 0x20
-#define BIP 0x40
-/*---------------------*/
-
-#define M0 0x00
-#define M2 0x04
-
-#define C0 0x00
-#define C1 0x40
-#define C2 0x80
-#define RWLH 0x30
+static struct das6402_boardinfo das6402_boards[] = {
+ {
+ .name = "das6402-12",
+ .maxdata = 0x0fff,
+ }, {
+ .name = "das6402-16",
+ .maxdata = 0xffff,
+ },
+};
struct das6402_private {
- int ai_bytes_to_read;
+ unsigned int irq;
- int das6402_ignoreirq;
+ unsigned int count;
+ unsigned int divider1;
+ unsigned int divider2;
+
+ unsigned int ao_range;
+ unsigned int ao_readback[2];
};
-static void das6402_ai_fifo_dregs(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static void das6402_set_mode(struct comedi_device *dev,
+ unsigned int mode)
{
- while (1) {
- if (!(inb(dev->iobase + 8) & 0x01))
- return;
- comedi_buf_put(s->async, inw(dev->iobase));
- }
+ outb(DAS6402_MODE_ENHANCED | mode, dev->iobase + DAS6402_MODE_REG);
}
-static void das6402_setcounter(struct comedi_device *dev)
+static void das6402_set_extended(struct comedi_device *dev,
+ unsigned int val)
{
- BYTE p;
- unsigned short ctrlwrd;
-
- /* set up counter0 first, mode 0 */
- p = M0 | C0 | RWLH;
- outb_p(p, dev->iobase + 15);
- ctrlwrd = 2000;
- p = (BYTE) (0xff & ctrlwrd);
- outb_p(p, dev->iobase + 12);
- p = (BYTE) (0xff & (ctrlwrd >> 8));
- outb_p(p, dev->iobase + 12);
-
- /* set up counter1, mode 2 */
- p = M2 | C1 | RWLH;
- outb_p(p, dev->iobase + 15);
- ctrlwrd = 10;
- p = (BYTE) (0xff & ctrlwrd);
- outb_p(p, dev->iobase + 13);
- p = (BYTE) (0xff & (ctrlwrd >> 8));
- outb_p(p, dev->iobase + 13);
-
- /* set up counter1, mode 2 */
- p = M2 | C2 | RWLH;
- outb_p(p, dev->iobase + 15);
- ctrlwrd = 1000;
- p = (BYTE) (0xff & ctrlwrd);
- outb_p(p, dev->iobase + 14);
- p = (BYTE) (0xff & (ctrlwrd >> 8));
- outb_p(p, dev->iobase + 14);
+ outb(DAS6402_STATUS_W_EXTEND, dev->iobase + DAS6402_STATUS_REG);
+ outb(DAS6402_STATUS_W_EXTEND | val, dev->iobase + DAS6402_STATUS_REG);
+ outb(val, dev->iobase + DAS6402_STATUS_REG);
}
-static irqreturn_t intr_handler(int irq, void *d)
+static void das6402_clear_all_interrupts(struct comedi_device *dev)
+{
+ outb(DAS6402_STATUS_W_CLRINT |
+ DAS6402_STATUS_W_CLRXTR |
+ DAS6402_STATUS_W_CLRXIN, dev->iobase + DAS6402_STATUS_REG);
+}
+
+static void das6402_ai_clear_eoc(struct comedi_device *dev)
+{
+ outb(DAS6402_STATUS_W_CLRINT, dev->iobase + DAS6402_STATUS_REG);
+}
+
+static void das6402_enable_counter(struct comedi_device *dev, bool load)
{
- struct comedi_device *dev = d;
struct das6402_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
+ unsigned long timer_iobase = dev->iobase + DAS6402_TIMER_BASE;
- if (!dev->attached || devpriv->das6402_ignoreirq) {
- dev_warn(dev->class_dev, "BUG: spurious interrupt\n");
- return IRQ_HANDLED;
- }
-#ifdef DEBUG
- printk("das6402: interrupt! das6402_irqcount=%i\n",
- devpriv->das6402_irqcount);
- printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2));
-#endif
-
- das6402_ai_fifo_dregs(dev, s);
-
- if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) {
- outw_p(SCANL, dev->iobase + 2); /* clears the fifo */
- outb(0x07, dev->iobase + 8); /* clears all flip-flops */
-#ifdef DEBUG
- printk("das6402: Got %i samples\n\n",
- devpriv->das6402_wordsread - diff);
-#endif
- s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
+ if (load) {
+ i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_iobase, 0, 1, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_iobase, 0, 2, I8254_MODE2 | I8254_BINARY);
+
+ i8254_write(timer_iobase, 0, 0, devpriv->count);
+ i8254_write(timer_iobase, 0, 1, devpriv->divider1);
+ i8254_write(timer_iobase, 0, 2, devpriv->divider2);
+
+ } else {
+ i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_iobase, 0, 1, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_iobase, 0, 2, I8254_MODE0 | I8254_BINARY);
}
+}
- outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */
+static irqreturn_t das6402_interrupt(int irq, void *d)
+{
+ struct comedi_device *dev = d;
+
+ das6402_clear_all_interrupts(dev);
- comedi_event(dev, s);
return IRQ_HANDLED;
}
-#if 0
-static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
+static int das6402_ai_cmd(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- int i;
+ return -EINVAL;
+}
- for (i = 0; i < n; i++)
- data[i] = inw(dev->iobase);
+static int das6402_ai_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ return -EINVAL;
}
-#endif
static int das6402_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
+ outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG);
+
+ return 0;
+}
+
+static void das6402_ai_soft_trig(struct comedi_device *dev)
+{
+ outw(0, dev->iobase + DAS6402_AI_DATA_REG);
+}
+
+static int das6402_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + DAS6402_STATUS_REG);
+ if (status & DAS6402_STATUS_FFNE)
+ return 0;
+ return -EBUSY;
+}
+
+static int das6402_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int aref = CR_AREF(insn->chanspec);
+ unsigned int val;
+ int ret;
+ int i;
+
+ val = DAS6402_MODE_RANGE(range) | DAS6402_MODE_POLLED;
+ if (aref == AREF_DIFF) {
+ if (chan > s->n_chan / 2)
+ return -EINVAL;
+ } else {
+ val |= DAS6402_MODE_SE;
+ }
+ if (comedi_range_is_unipolar(s, range))
+ val |= DAS6402_MODE_UNI;
+
+ /* enable software conversion trigger */
+ outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG);
+
+ das6402_set_mode(dev, val);
+
+ /* load the mux for single channel conversion */
+ outw(DAS6402_AI_MUX_HI(chan) | DAS6402_AI_MUX_LO(chan),
+ dev->iobase + DAS6402_AI_MUX_REG);
+
+ for (i = 0; i < insn->n; i++) {
+ das6402_ai_clear_eoc(dev);
+ das6402_ai_soft_trig(dev);
+
+ ret = comedi_timeout(dev, s, insn, das6402_ai_eoc, 0);
+ if (ret)
+ break;
+
+ val = inw(dev->iobase + DAS6402_AI_DATA_REG);
+
+ if (s->maxdata == 0x0fff)
+ val >>= 4;
+
+ data[i] = val;
+ }
+
+ das6402_ai_clear_eoc(dev);
+
+ return insn->n;
+}
+
+static int das6402_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
struct das6402_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int val;
+ int i;
+
+ /* set the range for this channel */
+ val = devpriv->ao_range;
+ val &= ~DAS6402_AO_RANGE_MASK(chan);
+ val |= DAS6402_AO_RANGE(chan, range);
+ if (val != devpriv->ao_range) {
+ devpriv->ao_range = val;
+ outb(val, dev->iobase + DAS6402_TRIG_REG);
+ }
/*
- * This function should reset the board from whatever condition it
- * is in (i.e., acquiring data), to a non-active state.
+ * The DAS6402/16 has a jumper to select either individual
+ * update (UPDATE) or simultaneous updating (XFER) of both
+ * DAC's. In UPDATE mode, when the MSB is written, that DAC
+ * is updated. In XFER mode, after both DAC's are loaded,
+ * a read cycle of any DAC register will update both DAC's
+ * simultaneously.
+ *
+ * If you have XFER mode enabled a (*insn_read) will need
+ * to be performed in order to update the DAC's with the
+ * last value written.
*/
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+
+ devpriv->ao_readback[chan] = val;
+
+ if (s->maxdata == 0x0fff) {
+ /*
+ * DAS6402/12 has the two 8-bit DAC registers, left
+ * justified (the 4 LSB bits are don't care). Data
+ * can be written as one word.
+ */
+ val <<= 4;
+ outw(val, dev->iobase + DAS6402_AO_DATA_REG(chan));
+ } else {
+ /*
+ * DAS6402/16 uses both 8-bit DAC registers and needs
+ * to be written LSB then MSB.
+ */
+ outb(val & 0xff,
+ dev->iobase + DAS6402_AO_LSB_REG(chan));
+ outb((val >> 8) & 0xff,
+ dev->iobase + DAS6402_AO_LSB_REG(chan));
+ }
+ }
- devpriv->das6402_ignoreirq = 1;
- dev_dbg(dev->class_dev, "Stopping acquisition\n");
- devpriv->das6402_ignoreirq = 1;
- outb_p(0x02, dev->iobase + 10); /* disable external trigging */
- outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
- outb_p(0, dev->iobase + 9); /* disables interrupts */
-
- outw_p(SCANL, dev->iobase + 2);
-
- return 0;
+ return insn->n;
}
-#ifdef unused
-static int das6402_ai_mode2(struct comedi_device *dev,
- struct comedi_subdevice *s, comedi_trig * it)
+static int das6402_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct das6402_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ /*
+ * If XFER mode is enabled, reading any DAC register
+ * will update both DAC's simultaneously.
+ */
+ inw(dev->iobase + DAS6402_AO_LSB_REG(chan));
- devpriv->das6402_ignoreirq = 1;
- dev_dbg(dev->class_dev, "Starting acquisition\n");
- outb_p(0x03, dev->iobase + 10); /* enable external trigging */
- outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */
- outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9);
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
- devpriv->ai_bytes_to_read = it->n * sizeof(short);
+ return insn->n;
+}
- /* um... ignoreirq is a nasty race condition */
- devpriv->das6402_ignoreirq = 0;
+static int das6402_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ data[1] = inb(dev->iobase + DAS6402_DI_DO_REG);
- outw_p(SCANL, dev->iobase + 2);
+ return insn->n;
+}
- return 0;
+static int das6402_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (comedi_dio_update_state(s, data))
+ outb(s->state, dev->iobase + DAS6402_DI_DO_REG);
+
+ data[1] = s->state;
+
+ return insn->n;
}
-#endif
-static int board_init(struct comedi_device *dev)
+static void das6402_reset(struct comedi_device *dev)
{
struct das6402_private *devpriv = dev->private;
- BYTE b;
-
- devpriv->das6402_ignoreirq = 1;
- outb(0x07, dev->iobase + 8);
+ /* enable "Enhanced" mode */
+ outb(DAS6402_MODE_ENHANCED, dev->iobase + DAS6402_MODE_REG);
- /* register 11 */
- outb_p(MODE, dev->iobase + 11);
- b = BIP | SEM | MODE | GAIN | FIFOHFULL;
- outb_p(b, dev->iobase + 11);
+ /* enable 10MHz pacer clock */
+ das6402_set_extended(dev, DAS6402_STATUS_W_10MHZ);
- /* register 8 */
- outb_p(EXTEND, dev->iobase + 8);
- b = EXTEND | MHZ;
- outb_p(b, dev->iobase + 8);
- b = MHZ | CLRINT | CLRXTR | CLRXIN;
- outb_p(b, dev->iobase + 8);
+ /* enable software conversion trigger */
+ outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG);
- /* register 9 */
- b = IRQ | CONVSRC | BURSTEN | INTE;
- outb_p(b, dev->iobase + 9);
+ /* default ADC to single-ended unipolar 10V inputs */
+ das6402_set_mode(dev, DAS6402_MODE_RANGE(0) |
+ DAS6402_MODE_POLLED |
+ DAS6402_MODE_SE |
+ DAS6402_MODE_UNI);
- /* register 10 */
- b = TGSEL | TGEN;
- outb_p(b, dev->iobase + 10);
+ /* default mux for single channel conversion (channel 0) */
+ outw(DAS6402_AI_MUX_HI(0) | DAS6402_AI_MUX_LO(0),
+ dev->iobase + DAS6402_AI_MUX_REG);
- b = 0x07;
- outb_p(b, dev->iobase + 8);
+ /* set both DAC's for unipolar 5V output range */
+ devpriv->ao_range = DAS6402_AO_RANGE(0, 2) | DAS6402_AO_RANGE(1, 2);
+ outb(devpriv->ao_range, dev->iobase + DAS6402_TRIG_REG);
- das6402_setcounter(dev);
+ /* set both DAC's to 0V */
+ outw(0, dev->iobase + DAS6402_AO_DATA_REG(0));
+ outw(0, dev->iobase + DAS6402_AO_DATA_REG(0));
+ inw(dev->iobase + DAS6402_AO_LSB_REG(0));
- outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
+ das6402_enable_counter(dev, false);
- devpriv->das6402_ignoreirq = 0;
+ /* set all digital outputs low */
+ outb(0, dev->iobase + DAS6402_DI_DO_REG);
- return 0;
+ das6402_clear_all_interrupts(dev);
}
static int das6402_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
+ const struct das6402_boardinfo *board = comedi_board(dev);
struct das6402_private *devpriv;
- unsigned int irq;
- int ret;
struct comedi_subdevice *s;
-
- ret = comedi_request_region(dev, it->options[0], DAS6402_SIZE);
- if (ret)
- return ret;
-
- irq = it->options[0];
- dev_dbg(dev->class_dev, "( irq = %u )\n", irq);
- ret = request_irq(irq, intr_handler, 0, "das6402", dev);
- if (ret < 0)
- return ret;
-
- dev->irq = irq;
+ int ret;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- ret = comedi_alloc_subdevices(dev, 1);
+ ret = comedi_request_region(dev, it->options[0], 0x10);
if (ret)
return ret;
- /* ai subdevice */
+ das6402_reset(dev);
+
+ /* IRQs 2,3,5,6,7, 10,11,15 are valid for "enhanced" mode */
+ if ((1 << it->options[1]) & 0x8cec) {
+ ret = request_irq(it->options[1], das6402_interrupt, 0,
+ dev->board_name, dev);
+ if (ret == 0) {
+ dev->irq = it->options[1];
+
+ switch (dev->irq) {
+ case 10:
+ devpriv->irq = 4;
+ break;
+ case 11:
+ devpriv->irq = 1;
+ break;
+ case 15:
+ devpriv->irq = 6;
+ break;
+ default:
+ devpriv->irq = dev->irq;
+ break;
+ }
+ }
+ }
+
+ ret = comedi_alloc_subdevices(dev, 4);
+ if (ret)
+ return ret;
+
+ /* Analog Input subdevice */
s = &dev->subdevices[0];
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND;
- s->n_chan = 8;
- /* s->trig[2]=das6402_ai_mode2; */
- s->cancel = das6402_ai_cancel;
- s->maxdata = (1 << 12) - 1;
- s->len_chanlist = 16; /* ? */
- s->range_table = &range_unknown;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
+ s->n_chan = 64;
+ s->maxdata = board->maxdata;
+ s->range_table = &das6402_ai_ranges;
+ s->insn_read = das6402_ai_insn_read;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = s->n_chan;
+ s->do_cmdtest = das6402_ai_cmdtest;
+ s->do_cmd = das6402_ai_cmd;
+ s->cancel = das6402_ai_cancel;
+ }
- board_init(dev);
+ /* Analog Output subdevice */
+ s = &dev->subdevices[1];
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 2;
+ s->maxdata = board->maxdata;
+ s->range_table = &das6402_ao_ranges;
+ s->insn_write = das6402_ao_insn_write;
+ s->insn_read = das6402_ao_insn_read;
+
+ /* Digital Input subdevice */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = das6402_di_insn_bits;
+
+ /* Digital Input subdevice */
+ s = &dev->subdevices[3];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = das6402_do_insn_bits;
return 0;
}
@@ -322,9 +536,12 @@ static struct comedi_driver das6402_driver = {
.module = THIS_MODULE,
.attach = das6402_attach,
.detach = comedi_legacy_detach,
+ .board_name = &das6402_boards[0].name,
+ .num_names = ARRAY_SIZE(das6402_boards),
+ .offset = sizeof(struct das6402_boardinfo),
};
module_comedi_driver(das6402_driver)
-MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_DESCRIPTION("Comedi driver for DAS6402 compatible boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index 5af0a5764a8..6f7f8d531dd 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -224,7 +224,6 @@ struct das800_private {
unsigned int divisor1; /* counter 1 value for timed conversions */
unsigned int divisor2; /* counter 2 value for timed conversions */
unsigned int do_bits; /* digital output bits */
- bool forever; /* flag that we should take data forever */
};
static void das800_ind_write(struct comedi_device *dev,
@@ -275,31 +274,54 @@ static void das800_disable(struct comedi_device *dev)
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
}
-static int das800_set_frequency(struct comedi_device *dev)
+static void das800_set_frequency(struct comedi_device *dev)
{
struct das800_private *devpriv = dev->private;
- int err = 0;
-
- if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2))
- err++;
- if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2))
- err++;
- if (err)
- return -1;
+ unsigned long timer_base = dev->iobase + DAS800_8254;
- return 0;
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
+ i8254_write(timer_base, 0, 1, devpriv->divisor1);
+ i8254_write(timer_base, 0, 2, devpriv->divisor2);
}
static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct das800_private *devpriv = dev->private;
- devpriv->forever = false;
devpriv->count = 0;
das800_disable(dev);
return 0;
}
+static int das800_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
+ unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
+ int i;
+
+ for (i = 1; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+ unsigned int range = CR_RANGE(cmd->chanlist[i]);
+
+ if (chan != (chan0 + i) % s->n_chan) {
+ dev_dbg(dev->class_dev,
+ "chanlist must be consecutive, counting upwards\n");
+ return -EINVAL;
+ }
+
+ if (range != range0) {
+ dev_dbg(dev->class_dev,
+ "chanlist must all have the same gain\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int das800_ai_do_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
@@ -307,6 +329,7 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev,
const struct das800_board *thisboard = comedi_board(dev);
struct das800_private *devpriv = dev->private;
int err = 0;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -352,41 +375,20 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->convert_src == TRIG_TIMER) {
- int tmp = cmd->convert_arg;
-
- /* calculate counter values that give desired timing */
+ arg = cmd->convert_arg;
i8253_cascade_ns_to_timer(I8254_OSC_BASE_1MHZ,
&devpriv->divisor1,
&devpriv->divisor2,
- &cmd->convert_arg, cmd->flags);
- if (tmp != cmd->convert_arg)
- err++;
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
}
if (err)
return 4;
- /* check channel/gain list against card's limitations */
- if (cmd->chanlist) {
- unsigned int chan = CR_CHAN(cmd->chanlist[0]);
- unsigned int range = CR_RANGE(cmd->chanlist[0]);
- unsigned int next;
- int i;
-
- for (i = 1; i < cmd->chanlist_len; i++) {
- next = cmd->chanlist[i];
- if (CR_CHAN(next) != (chan + i) % N_CHAN_AI) {
- dev_err(dev->class_dev,
- "chanlist must be consecutive, counting upwards\n");
- err++;
- }
- if (CR_RANGE(next) != range) {
- dev_err(dev->class_dev,
- "chanlist must all have the same gain\n");
- err++;
- }
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= das800_ai_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -400,9 +402,10 @@ static int das800_ai_do_cmd(struct comedi_device *dev,
const struct das800_board *thisboard = comedi_board(dev);
struct das800_private *devpriv = dev->private;
struct comedi_async *async = s->async;
- unsigned int gain = CR_RANGE(async->cmd.chanlist[0]);
- unsigned int start_chan = CR_CHAN(async->cmd.chanlist[0]);
- unsigned int end_chan = (start_chan + async->cmd.chanlist_len - 1) % 8;
+ struct comedi_cmd *cmd = &async->cmd;
+ unsigned int gain = CR_RANGE(cmd->chanlist[0]);
+ unsigned int start_chan = CR_CHAN(cmd->chanlist[0]);
+ unsigned int end_chan = (start_chan + cmd->chanlist_len - 1) % 8;
unsigned int scan_chans = (end_chan << 3) | start_chan;
int conv_bits;
unsigned long irq_flags;
@@ -420,46 +423,28 @@ static int das800_ai_do_cmd(struct comedi_device *dev,
gain &= 0xf;
outb(gain, dev->iobase + DAS800_GAIN);
- switch (async->cmd.stop_src) {
- case TRIG_COUNT:
- devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len;
- devpriv->forever = false;
- break;
- case TRIG_NONE:
- devpriv->forever = true;
+ if (cmd->stop_src == TRIG_COUNT)
+ devpriv->count = cmd->stop_arg * cmd->chanlist_len;
+ else /* TRIG_NONE */
devpriv->count = 0;
- break;
- default:
- break;
- }
/* enable auto channel scan, send interrupts on end of conversion
* and set clock source to internal or external
*/
conv_bits = 0;
conv_bits |= EACS | IEOC;
- if (async->cmd.start_src == TRIG_EXT)
+ if (cmd->start_src == TRIG_EXT)
conv_bits |= DTEN;
- switch (async->cmd.convert_src) {
- case TRIG_TIMER:
+ if (cmd->convert_src == TRIG_TIMER) {
conv_bits |= CASC | ITE;
/* set conversion frequency */
- if (das800_set_frequency(dev) < 0) {
- comedi_error(dev, "Error setting up counters");
- return -1;
- }
- break;
- case TRIG_EXT:
- break;
- default:
- break;
+ das800_set_frequency(dev);
}
spin_lock_irqsave(&dev->spinlock, irq_flags);
das800_ind_write(dev, conv_bits, CONV_CONTROL);
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
- async->events = 0;
das800_enable(dev);
return 0;
}
@@ -477,7 +462,8 @@ static irqreturn_t das800_interrupt(int irq, void *d)
struct comedi_device *dev = d;
struct das800_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
- struct comedi_async *async = s ? s->async : NULL;
+ struct comedi_async *async;
+ struct comedi_cmd *cmd;
unsigned long irq_flags;
unsigned int status;
unsigned int val;
@@ -491,6 +477,9 @@ static irqreturn_t das800_interrupt(int irq, void *d)
if (!dev->attached)
return IRQ_HANDLED;
+ async = s->async;
+ cmd = &async->cmd;
+
spin_lock_irqsave(&dev->spinlock, irq_flags);
status = das800_ind_read(dev, CONTROL1) & STATUS2_HCEN;
/*
@@ -522,7 +511,7 @@ static irqreturn_t das800_interrupt(int irq, void *d)
val >>= 4; /* 12-bit sample */
/* if there are more data points to collect */
- if (devpriv->count > 0 || devpriv->forever) {
+ if (cmd->stop_src == TRIG_NONE || devpriv->count > 0) {
/* write data point to buffer */
cfc_write_to_buffer(s, val & s->maxdata);
devpriv->count--;
@@ -532,14 +521,12 @@ static irqreturn_t das800_interrupt(int irq, void *d)
if (fifo_overflow) {
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
- das800_cancel(dev, s);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
- async->events = 0;
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
- if (devpriv->count > 0 || devpriv->forever) {
+ if (cmd->stop_src == TRIG_NONE || devpriv->count > 0) {
/* Re-enable card's interrupt.
* We already have spinlock, so indirect addressing is safe */
das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits,
@@ -551,20 +538,21 @@ static irqreturn_t das800_interrupt(int irq, void *d)
das800_disable(dev);
async->events |= COMEDI_CB_EOA;
}
- comedi_event(dev, s);
- async->events = 0;
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
-static int das800_wait_for_conv(struct comedi_device *dev, int timeout)
+static int das800_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- int i;
+ unsigned int status;
- for (i = 0; i < timeout; i++) {
- if (!(inb(dev->iobase + DAS800_STATUS) & BUSY))
- return 0;
- }
- return -ETIME;
+ status = inb(dev->iobase + DAS800_STATUS);
+ if ((status & BUSY) == 0)
+ return 0;
+ return -EBUSY;
}
static int das800_ai_insn_read(struct comedi_device *dev,
@@ -599,7 +587,7 @@ static int das800_ai_insn_read(struct comedi_device *dev,
/* trigger conversion */
outb_p(0, dev->iobase + DAS800_MSB);
- ret = das800_wait_for_conv(dev, 1000);
+ ret = comedi_timeout(dev, s, insn, das800_ai_eoc, 0);
if (ret)
return ret;
@@ -686,7 +674,7 @@ static int das800_probe(struct comedi_device *dev)
static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct das800_board *thisboard = comedi_board(dev);
+ const struct das800_board *thisboard;
struct das800_private *devpriv;
struct comedi_subdevice *s;
unsigned int irq = it->options[1];
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index b04a5633f75..ad7a5d53b97 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -124,13 +124,12 @@ Configuration Options:
/* board AI ranges in comedi structure */
static const struct comedi_lrange dmm32at_airanges = {
- 4,
- {
- UNI_RANGE(10),
- UNI_RANGE(5),
- BIP_RANGE(10),
- BIP_RANGE(5),
- }
+ 4, {
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ BIP_RANGE(10),
+ BIP_RANGE(5)
+ }
};
/* register values for above ranges */
@@ -145,13 +144,12 @@ static const unsigned char dmm32at_rangebits[] = {
* board. The application should only use the range set by the jumper
*/
static const struct comedi_lrange dmm32at_aoranges = {
- 4,
- {
- UNI_RANGE(10),
- UNI_RANGE(5),
- BIP_RANGE(10),
- BIP_RANGE(5),
- }
+ 4, {
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ BIP_RANGE(10),
+ BIP_RANGE(5)
+ }
};
struct dmm32at_private {
@@ -166,24 +164,35 @@ struct dmm32at_private {
};
+static int dmm32at_ai_status(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned char status;
+
+ status = inb(dev->iobase + context);
+ if ((status & DMM32AT_STATUS) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int dmm32at_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- int n, i;
+ int n;
unsigned int d;
- unsigned char status;
unsigned short msb, lsb;
unsigned char chan;
int range;
+ int ret;
/* get the channel and range number */
chan = CR_CHAN(insn->chanspec) & (s->n_chan - 1);
range = CR_RANGE(insn->chanspec);
- /* printk("channel=0x%02x, range=%d\n",chan,range); */
-
/* zero scan and fifo control and reset fifo */
outb(DMM32AT_FIFORESET, dev->iobase + DMM32AT_FIFOCNTRL);
@@ -194,30 +203,20 @@ static int dmm32at_ai_rinsn(struct comedi_device *dev,
outb(dmm32at_rangebits[range], dev->iobase + DMM32AT_AICONF);
/* wait for circuit to settle */
- for (i = 0; i < 40000; i++) {
- status = inb(dev->iobase + DMM32AT_AIRBACK);
- if ((status & DMM32AT_STATUS) == 0)
- break;
- }
- if (i == 40000) {
- printk(KERN_WARNING "dmm32at: timeout\n");
- return -ETIMEDOUT;
- }
+ ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, DMM32AT_AIRBACK);
+ if (ret)
+ return ret;
/* convert n samples */
for (n = 0; n < insn->n; n++) {
/* trigger conversion */
outb(0xff, dev->iobase + DMM32AT_CONV);
+
/* wait for conversion to end */
- for (i = 0; i < 40000; i++) {
- status = inb(dev->iobase + DMM32AT_AISTAT);
- if ((status & DMM32AT_STATUS) == 0)
- break;
- }
- if (i == 40000) {
- printk(KERN_WARNING "dmm32at: timeout\n");
- return -ETIMEDOUT;
- }
+ ret = comedi_timeout(dev, s, insn, dmm32at_ai_status,
+ DMM32AT_AISTAT);
+ if (ret)
+ return ret;
/* read data */
lsb = inb(dev->iobase + DMM32AT_AILSB);
@@ -244,13 +243,39 @@ static int dmm32at_ns_to_timer(unsigned int *ns, int round)
return *ns;
}
+static int dmm32at_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
+ unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
+ int i;
+
+ for (i = 1; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+ unsigned int range = CR_RANGE(cmd->chanlist[i]);
+
+ if (chan != (chan0 + i) % s->n_chan) {
+ dev_dbg(dev->class_dev,
+ "entries in chanlist must be consecutive channels, counting upwards\n");
+ return -EINVAL;
+ }
+ if (range != range0) {
+ dev_dbg(dev->class_dev,
+ "entries in chanlist must all have the same gain\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int dmm32at_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
int err = 0;
- int tmp;
- int start_chan, gain, i;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -326,50 +351,28 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
- dmm32at_ns_to_timer(&cmd->scan_begin_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->scan_begin_arg)
- err++;
+ arg = cmd->scan_begin_arg;
+ dmm32at_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
- dmm32at_ns_to_timer(&cmd->convert_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->convert_arg)
- err++;
- if (cmd->scan_begin_src == TRIG_TIMER &&
- cmd->scan_begin_arg <
- cmd->convert_arg * cmd->scan_end_arg) {
- cmd->scan_begin_arg =
- cmd->convert_arg * cmd->scan_end_arg;
- err++;
+ arg = cmd->convert_arg;
+ dmm32at_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
+
+ if (cmd->scan_begin_src == TRIG_TIMER) {
+ arg = cmd->convert_arg * cmd->scan_end_arg;
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ arg);
}
}
if (err)
return 4;
- /* step 5 check the channel list, the channel list for this
- board must be consecutive and gains must be the same */
-
- if (cmd->chanlist) {
- gain = CR_RANGE(cmd->chanlist[0]);
- start_chan = CR_CHAN(cmd->chanlist[0]);
- for (i = 1; i < cmd->chanlist_len; i++) {
- if (CR_CHAN(cmd->chanlist[i]) !=
- (start_chan + i) % s->n_chan) {
- comedi_error(dev,
- "entries in chanlist must be consecutive channels, counting upwards\n");
- err++;
- }
- if (CR_RANGE(cmd->chanlist[i]) != gain) {
- comedi_error(dev,
- "entries in chanlist must all have the same gain\n");
- err++;
- }
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= dmm32at_ai_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -411,8 +414,9 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct dmm32at_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
- int i, range;
- unsigned char chanlo, chanhi, status;
+ int range;
+ unsigned char chanlo, chanhi;
+ int ret;
if (!cmd->chanlist)
return -EINVAL;
@@ -447,16 +451,13 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* isr */
}
- /* wait for circuit to settle */
- for (i = 0; i < 40000; i++) {
- status = inb(dev->iobase + DMM32AT_AIRBACK);
- if ((status & DMM32AT_STATUS) == 0)
- break;
- }
- if (i == 40000) {
- printk(KERN_WARNING "dmm32at: timeout\n");
- return -ETIMEDOUT;
- }
+ /*
+ * wait for circuit to settle
+ * we don't have the 'insn' here but it's not needed
+ */
+ ret = comedi_timeout(dev, s, NULL, dmm32at_ai_status, DMM32AT_AIRBACK);
+ if (ret)
+ return ret;
if (devpriv->ai_scans_left > 1) {
/* start the clock and enable the interrupts */
@@ -467,14 +468,6 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
outb(0xff, dev->iobase + DMM32AT_CONV);
}
-/* printk("dmmat32 in command\n"); */
-
-/* for(i=0;i<cmd->chanlist_len;i++) */
-/* comedi_buf_put(s->async,i*100); */
-
-/* s->async->events |= COMEDI_CB_EOA; */
-/* comedi_event(dev, s); */
-
return 0;
}
@@ -515,7 +508,7 @@ static irqreturn_t dmm32at_isr(int irq, void *d)
/* invert sign bit to make range unsigned */
samp = ((msb ^ 0x0080) << 8) + lsb;
- comedi_buf_put(s->async, samp);
+ comedi_buf_put(s, samp);
}
if (devpriv->ai_scans_left != 0xffffffff) { /* TRIG_COUNT */
@@ -537,6 +530,19 @@ static irqreturn_t dmm32at_isr(int irq, void *d)
return IRQ_HANDLED;
}
+static int dmm32at_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned char status;
+
+ status = inb(dev->iobase + DMM32AT_DACSTAT);
+ if ((status & DMM32AT_DACBUSY) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int dmm32at_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -545,6 +551,7 @@ static int dmm32at_ao_winsn(struct comedi_device *dev,
int i;
int chan = CR_CHAN(insn->chanspec);
unsigned char hi, lo, status;
+ int ret;
/* Writing a list of values to an AO channel is probably not
* very useful, but that's how the interface is defined. */
@@ -556,21 +563,15 @@ static int dmm32at_ao_winsn(struct comedi_device *dev,
lo = data[i] & 0x00ff;
/* high byte also contains channel number */
hi = (data[i] >> 8) + chan * (1 << 6);
- /* printk("writing 0x%02x 0x%02x\n",hi,lo); */
/* write the low and high values to the board */
outb(lo, dev->iobase + DMM32AT_DACLSB);
outb(hi, dev->iobase + DMM32AT_DACMSB);
/* wait for circuit to settle */
- for (i = 0; i < 40000; i++) {
- status = inb(dev->iobase + DMM32AT_DACSTAT);
- if ((status & DMM32AT_DACBUSY) == 0)
- break;
- }
- if (i == 40000) {
- printk(KERN_WARNING "dmm32at: timeout\n");
- return -ETIMEDOUT;
- }
+ ret = comedi_timeout(dev, s, insn, dmm32at_ao_eoc, 0);
+ if (ret)
+ return ret;
+
/* dummy read to update trigger the output */
status = inb(dev->iobase + DMM32AT_DACMSB);
@@ -682,9 +683,6 @@ static int dmm32at_attach(struct comedi_device *dev,
int ret;
struct comedi_subdevice *s;
unsigned char aihi, ailo, fifostat, aistat, intstat, airback;
- unsigned int irq;
-
- irq = it->options[1];
ret = comedi_request_region(dev, it->options[0], DMM32AT_MEMSIZE);
if (ret)
@@ -723,26 +721,17 @@ static int dmm32at_attach(struct comedi_device *dev,
intstat = inb(dev->iobase + DMM32AT_INTCLOCK);
airback = inb(dev->iobase + DMM32AT_AIRBACK);
- printk(KERN_DEBUG "dmm32at: lo=0x%02x hi=0x%02x fifostat=0x%02x\n",
- ailo, aihi, fifostat);
- printk(KERN_DEBUG
- "dmm32at: aistat=0x%02x intstat=0x%02x airback=0x%02x\n",
- aistat, intstat, airback);
-
if ((ailo != 0x00) || (aihi != 0x1f) || (fifostat != 0x80) ||
(aistat != 0x60 || (intstat != 0x00) || airback != 0x0c)) {
- printk(KERN_ERR "dmmat32: board detection failed\n");
+ dev_err(dev->class_dev, "board detection failed\n");
return -EIO;
}
- /* board is there, register interrupt */
- if (irq) {
- ret = request_irq(irq, dmm32at_isr, 0, dev->board_name, dev);
- if (ret < 0) {
- printk(KERN_ERR "dmm32at: irq conflict\n");
- return ret;
- }
- dev->irq = irq;
+ if (it->options[1]) {
+ ret = request_irq(it->options[1], dmm32at_isr, 0,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = it->options[1];
}
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
@@ -754,20 +743,22 @@ static int dmm32at_attach(struct comedi_device *dev,
return ret;
s = &dev->subdevices[0];
- dev->read_subdev = s;
/* analog input subdevice */
s->type = COMEDI_SUBD_AI;
/* we support single-ended (ground) and differential */
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
s->n_chan = 32;
s->maxdata = 0xffff;
s->range_table = &dmm32at_airanges;
- s->len_chanlist = 32; /* This is the maximum chanlist length that
- the board can handle */
s->insn_read = dmm32at_ai_rinsn;
- s->do_cmd = dmm32at_ai_cmd;
- s->do_cmdtest = dmm32at_ai_cmdtest;
- s->cancel = dmm32at_ai_cancel;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = 32;
+ s->do_cmd = dmm32at_ai_cmd;
+ s->do_cmdtest = dmm32at_ai_cmdtest;
+ s->cancel = dmm32at_ai_cancel;
+ }
s = &dev->subdevices[1];
/* analog output subdevice */
@@ -799,11 +790,7 @@ static int dmm32at_attach(struct comedi_device *dev,
s->insn_bits = dmm32at_dio_insn_bits;
s->insn_config = dmm32at_dio_insn_config;
- /* success */
- printk(KERN_INFO "comedi%d: dmm32at: attached\n", dev->minor);
-
- return 1;
-
+ return 0;
}
static struct comedi_driver dmm32at_driver = {
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index 811c8c59c01..4263014426f 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -90,58 +90,42 @@ Configuration options:
#if 0
/* ignore 'defined but not used' warning */
-static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { 4, {
- RANGE(-10,
- 10),
- RANGE(-5,
- 5),
- RANGE
- (-2.5,
- 2.5),
- RANGE
- (-1.25,
- 1.25),
- }
+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, {
- RANGE(-10,
- 10),
- RANGE(-1,
- 1),
- RANGE
- (-0.1,
- 0.1),
- RANGE
- (-0.02,
- 0.02),
- }
+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, {
- RANGE(0,
- 10),
- RANGE(0,
- 5),
- RANGE(0,
- 2.5),
- RANGE(0,
- 1.25),
- }
+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, {
- RANGE(0,
- 10),
- RANGE(0,
- 1),
- RANGE(0,
- 0.1),
- RANGE(0,
- 0.02),
- }
+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 {
@@ -289,13 +273,6 @@ static int dt2801_writedata(struct comedi_device *dev, unsigned int data)
outb_p(data & 0xff, dev->iobase + DT2801_DATA);
return 0;
}
-#if 0
- if (stat & DT_S_READY) {
- printk
- ("dt2801: ready flag set (bad!) in dt2801_writedata()\n");
- return -EIO;
- }
-#endif
} while (--timeout > 0);
return -ETIME;
@@ -343,11 +320,11 @@ static int dt2801_writecmd(struct comedi_device *dev, int command)
stat = inb_p(dev->iobase + DT2801_STATUS);
if (stat & DT_S_COMPOSITE_ERROR) {
- printk
- ("dt2801: composite-error in dt2801_writecmd(), ignoring\n");
+ dev_dbg(dev->class_dev,
+ "composite-error in %s, ignoring\n", __func__);
}
if (!(stat & DT_S_READY))
- printk("dt2801: !ready in dt2801_writecmd(), ignoring\n");
+ dev_dbg(dev->class_dev, "!ready in %s, ignoring\n", __func__);
outb_p(command, dev->iobase + DT2801_CMD);
return 0;
@@ -359,17 +336,12 @@ static int dt2801_reset(struct comedi_device *dev)
unsigned int stat;
int timeout;
- DPRINTK("dt2801: resetting board...\n");
- DPRINTK("fingerprint: 0x%02x 0x%02x\n", inb_p(dev->iobase),
- inb_p(dev->iobase + 1));
-
/* 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);
- DPRINTK("dt2801: stop\n");
/* dt2801_writecmd(dev,DT_C_STOP); */
outb_p(DT_C_STOP, dev->iobase + DT2801_CMD);
@@ -382,12 +354,10 @@ static int dt2801_reset(struct comedi_device *dev)
break;
} while (timeout--);
if (!timeout)
- printk("dt2801: timeout 1 status=0x%02x\n", stat);
+ dev_dbg(dev->class_dev, "timeout 1 status=0x%02x\n", stat);
- /* printk("dt2801: reading dummy\n"); */
/* dt2801_readdata(dev,&board_code); */
- DPRINTK("dt2801: reset\n");
outb_p(DT_C_RESET, dev->iobase + DT2801_CMD);
/* dt2801_writecmd(dev,DT_C_RESET); */
@@ -399,13 +369,10 @@ static int dt2801_reset(struct comedi_device *dev)
break;
} while (timeout--);
if (!timeout)
- printk("dt2801: timeout 2 status=0x%02x\n", stat);
+ dev_dbg(dev->class_dev, "timeout 2 status=0x%02x\n", stat);
- DPRINTK("dt2801: reading code\n");
dt2801_readdata(dev, &board_code);
- DPRINTK("dt2801: ok. code=0x%02x\n", board_code);
-
return board_code;
}
@@ -465,12 +432,12 @@ static int dt2801_error(struct comedi_device *dev, int stat)
{
if (stat < 0) {
if (stat == -ETIME)
- printk("dt2801: timeout\n");
+ dev_dbg(dev->class_dev, "timeout\n");
else
- printk("dt2801: error %d\n", stat);
+ dev_dbg(dev->class_dev, "error %d\n", stat);
return stat;
}
- printk("dt2801: error status 0x%02x, resetting...\n", stat);
+ dev_dbg(dev->class_dev, "error status 0x%02x, resetting...\n", stat);
dt2801_reset(dev);
dt2801_reset(dev);
@@ -578,7 +545,7 @@ static int dt2801_dio_insn_config(struct comedi_device *dev,
*/
static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct dt2801_board *board = comedi_board(dev);
+ const struct dt2801_board *board;
struct dt2801_private *devpriv;
struct comedi_subdevice *s;
int board_code, type;
@@ -601,8 +568,8 @@ static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (boardtypes[type].boardcode == board_code)
goto havetype;
}
- printk("dt2801: unrecognized board code=0x%02x, contact author\n",
- board_code);
+ dev_dbg(dev->class_dev,
+ "unrecognized board code=0x%02x, contact author\n", board_code);
type = 0;
havetype:
diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c
index 0ca02fa7ba1..ba7c2ba618e 100644
--- a/drivers/staging/comedi/drivers/dt2811.c
+++ b/drivers/staging/comedi/drivers/dt2811.c
@@ -42,60 +42,59 @@ Configuration options:
*/
#include <linux/module.h>
-#include <linux/interrupt.h>
#include "../comedidev.h"
static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = {
4, {
- RANGE(0, 5),
- RANGE(0, 2.5),
- RANGE(0, 1.25),
- RANGE(0, 0.625)
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25),
+ UNI_RANGE(0.625)
}
};
static const struct comedi_lrange range_dt2811_pgh_ai_2_5_bipolar = {
4, {
- RANGE(-2.5, 2.5),
- RANGE(-1.25, 1.25),
- RANGE(-0.625, 0.625),
- RANGE(-0.3125, 0.3125)
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ BIP_RANGE(0.3125)
}
};
static const struct comedi_lrange range_dt2811_pgh_ai_5_bipolar = {
4, {
- RANGE(-5, 5),
- RANGE(-2.5, 2.5),
- RANGE(-1.25, 1.25),
- RANGE(-0.625, 0.625)
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625)
}
};
static const struct comedi_lrange range_dt2811_pgl_ai_5_unipolar = {
4, {
- RANGE(0, 5),
- RANGE(0, 0.5),
- RANGE(0, 0.05),
- RANGE(0, 0.01)
+ UNI_RANGE(5),
+ UNI_RANGE(0.5),
+ UNI_RANGE(0.05),
+ UNI_RANGE(0.01)
}
};
static const struct comedi_lrange range_dt2811_pgl_ai_2_5_bipolar = {
4, {
- RANGE(-2.5, 2.5),
- RANGE(-0.25, 0.25),
- RANGE(-0.025, 0.025),
- RANGE(-0.005, 0.005)
+ BIP_RANGE(2.5),
+ BIP_RANGE(0.25),
+ BIP_RANGE(0.025),
+ BIP_RANGE(0.005)
}
};
static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = {
4, {
- RANGE(-5, 5),
- RANGE(-0.5, 0.5),
- RANGE(-0.05, 0.05),
- RANGE(-0.01, 0.01)
+ BIP_RANGE(5),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.05),
+ BIP_RANGE(0.01)
}
};
@@ -225,50 +224,32 @@ static const struct comedi_lrange *dac_range_types[] = {
&range_unipolar5
};
-#define DT2811_TIMEOUT 5
-
-#if 0
-static irqreturn_t dt2811_interrupt(int irq, void *d)
+static int dt2811_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- int lo, hi;
- int data;
- struct comedi_device *dev = d;
- struct dt2811_private *devpriv = dev->private;
-
- if (!dev->attached) {
- comedi_error(dev, "spurious interrupt");
- return IRQ_HANDLED;
- }
-
- lo = inb(dev->iobase + DT2811_ADDATLO);
- hi = inb(dev->iobase + DT2811_ADDATHI);
-
- data = lo + (hi << 8);
+ unsigned int status;
- if (!(--devpriv->ntrig)) {
- /* how to turn off acquisition */
- s->async->events |= COMEDI_SB_EOA;
- }
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ status = inb(dev->iobase + DT2811_ADCSR);
+ if ((status & DT2811_ADBUSY) == 0)
+ return 0;
+ return -EBUSY;
}
-#endif
static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
int chan = CR_CHAN(insn->chanspec);
- int timeout = DT2811_TIMEOUT;
+ int ret;
int i;
for (i = 0; i < insn->n; i++) {
outb(chan, dev->iobase + DT2811_ADGCR);
- while (timeout
- && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
- timeout--;
- if (!timeout)
- return -ETIME;
+ ret = comedi_timeout(dev, s, insn, dt2811_ai_eoc, 0);
+ if (ret)
+ return ret;
data[i] = inb(dev->iobase + DT2811_ADDATLO);
data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
@@ -278,35 +259,6 @@ static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
return i;
}
-#if 0
-/* Wow. This is code from the Comedi stone age. But it hasn't been
- * replaced, so I'll let it stay. */
-int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
-{
- struct comedi_device *dev = comedi_devices + minor;
-
- if (adtrig->n < 1)
- return 0;
- dev->curadchan = adtrig->chan;
- switch (dev->i_admode) {
- case COMEDI_MDEMAND:
- dev->ntrig = adtrig->n - 1;
- /* not necessary */
- /*printk("dt2811: AD soft trigger\n"); */
- /*outb(DT2811_CLRERROR|DT2811_INTENB,
- dev->iobase+DT2811_ADCSR); */
- outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
- do_gettimeofday(&trigtime);
- break;
- case COMEDI_MCONTS:
- dev->ntrig = adtrig->n;
- break;
- }
-
- return 0;
-}
-#endif
-
static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
@@ -386,10 +338,7 @@ static int dt2811_do_insn_bits(struct comedi_device *dev,
*/
static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- /* int i, irq; */
- /* unsigned long irqs; */
- /* long flags; */
-
+ /* int i; */
const struct dt2811_board *board = comedi_board(dev);
struct dt2811_private *devpriv;
int ret;
@@ -406,45 +355,6 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
i = inb(dev->iobase + DT2811_ADDATHI);
#endif
-#if 0
- irq = it->options[1];
- if (irq < 0) {
- save_flags(flags);
- sti();
- irqs = probe_irq_on();
-
- outb(DT2811_CLRERROR | DT2811_INTENB,
- dev->iobase + DT2811_ADCSR);
- outb(0, dev->iobase + DT2811_ADGCR);
-
- udelay(100);
-
- irq = probe_irq_off(irqs);
- restore_flags(flags);
-
- /*outb(DT2811_CLRERROR|DT2811_INTENB,
- dev->iobase+DT2811_ADCSR);*/
-
- if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR)
- printk(KERN_ERR "error probing irq (bad)\n");
- dev->irq = 0;
- if (irq > 0) {
- i = inb(dev->iobase + DT2811_ADDATLO);
- i = inb(dev->iobase + DT2811_ADDATHI);
- printk(KERN_INFO "(irq = %d)\n", irq);
- ret = request_irq(irq, dt2811_interrupt, 0,
- dev->board_name, dev);
- if (ret < 0)
- return -EIO;
- dev->irq = irq;
- } else if (irq == 0) {
- printk(KERN_INFO "(no irq)\n");
- } else {
- printk(KERN_ERR "( multiple irq's -- this is bad! )\n");
- }
- }
-#endif
-
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c
index 6514b9e0055..904c9f0e4af 100644
--- a/drivers/staging/comedi/drivers/dt2814.c
+++ b/drivers/staging/comedi/drivers/dt2814.c
@@ -66,29 +66,35 @@ struct dt2814_private {
#define DT2814_TIMEOUT 10
#define DT2814_MAX_SPEED 100000 /* Arbitrary 10 khz limit */
+static int dt2814_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + DT2814_CSR);
+ if (status & DT2814_FINISH)
+ return 0;
+ return -EBUSY;
+}
+
static int dt2814_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- int n, i, hi, lo;
+ int n, hi, lo;
int chan;
- int status = 0;
+ int ret;
for (n = 0; n < insn->n; n++) {
chan = CR_CHAN(insn->chanspec);
outb(chan, dev->iobase + DT2814_CSR);
- for (i = 0; i < DT2814_TIMEOUT; i++) {
- status = inb(dev->iobase + DT2814_CSR);
- printk(KERN_INFO "dt2814: status: %02x\n", status);
- udelay(10);
- if (status & DT2814_FINISH)
- break;
- }
- if (i >= DT2814_TIMEOUT) {
- printk(KERN_INFO "dt2814: status: %02x\n", status);
- return -ETIMEDOUT;
- }
+
+ ret = comedi_timeout(dev, s, insn, dt2814_ai_eoc, 0);
+ if (ret)
+ return ret;
hi = inb(dev->iobase + DT2814_DATA);
lo = inb(dev->iobase + DT2814_DATA);
@@ -122,7 +128,7 @@ static int dt2814_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
int err = 0;
- int tmp;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -164,10 +170,9 @@ static int dt2814_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
- tmp = cmd->scan_begin_arg;
- dt2814_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->scan_begin_arg)
- err++;
+ arg = cmd->scan_begin_arg;
+ dt2814_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
if (err)
return 4;
@@ -200,7 +205,7 @@ static irqreturn_t dt2814_interrupt(int irq, void *d)
int lo, hi;
struct comedi_device *dev = d;
struct dt2814_private *devpriv = dev->private;
- struct comedi_subdevice *s;
+ struct comedi_subdevice *s = dev->read_subdev;
int data;
if (!dev->attached) {
@@ -208,8 +213,6 @@ static irqreturn_t dt2814_interrupt(int irq, void *d)
return IRQ_HANDLED;
}
- s = &dev->subdevices[0];
-
hi = inb(dev->iobase + DT2814_DATA);
lo = inb(dev->iobase + DT2814_DATA);
@@ -238,9 +241,9 @@ static irqreturn_t dt2814_interrupt(int irq, void *d)
static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct dt2814_private *devpriv;
- int i, irq;
- int ret;
struct comedi_subdevice *s;
+ int ret;
+ int i;
ret = comedi_request_region(dev, it->options[0], DT2814_SIZE);
if (ret)
@@ -249,49 +252,17 @@ static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it)
outb(0, dev->iobase + DT2814_CSR);
udelay(100);
if (inb(dev->iobase + DT2814_CSR) & DT2814_ERR) {
- printk(KERN_ERR "reset error (fatal)\n");
+ dev_err(dev->class_dev, "reset error (fatal)\n");
return -EIO;
}
i = inb(dev->iobase + DT2814_DATA);
i = inb(dev->iobase + DT2814_DATA);
- irq = it->options[1];
-#if 0
- if (irq < 0) {
- save_flags(flags);
- sti();
- irqs = probe_irq_on();
-
- outb(0, dev->iobase + DT2814_CSR);
-
- udelay(100);
-
- irq = probe_irq_off(irqs);
- restore_flags(flags);
- if (inb(dev->iobase + DT2814_CSR) & DT2814_ERR)
- printk(KERN_DEBUG "error probing irq (bad)\n");
-
-
- i = inb(dev->iobase + DT2814_DATA);
- i = inb(dev->iobase + DT2814_DATA);
- }
-#endif
- dev->irq = 0;
- if (irq > 0) {
- if (request_irq(irq, dt2814_interrupt, 0, "dt2814", dev)) {
- printk(KERN_WARNING "(irq %d unavailable)\n", irq);
- } else {
- printk(KERN_INFO "( irq = %d )\n", irq);
- dev->irq = irq;
- }
- } else if (irq == 0) {
- printk(KERN_WARNING "(no irq)\n");
- } else {
-#if 0
- printk(KERN_DEBUG "(probe returned multiple irqs--bad)\n");
-#else
- printk(KERN_WARNING "(irq probe not implemented)\n");
-#endif
+ if (it->options[1]) {
+ ret = request_irq(it->options[1], dt2814_interrupt, 0,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = it->options[1];
}
ret = comedi_alloc_subdevices(dev, 1);
@@ -303,16 +274,19 @@ static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -ENOMEM;
s = &dev->subdevices[0];
- dev->read_subdev = s;
s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND;
s->n_chan = 16; /* XXX */
- s->len_chanlist = 1;
s->insn_read = dt2814_ai_insn_read;
- s->do_cmd = dt2814_ai_cmd;
- s->do_cmdtest = dt2814_ai_cmdtest;
s->maxdata = 0xfff;
s->range_table = &range_unknown; /* XXX */
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = 1;
+ s->do_cmd = dt2814_ai_cmd;
+ s->do_cmdtest = dt2814_ai_cmdtest;
+ }
return 0;
}
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index 34040f0175e..b9ac4ed8bab 100644
--- a/drivers/staging/comedi/drivers/dt2815.c
+++ b/drivers/staging/comedi/drivers/dt2815.c
@@ -67,15 +67,17 @@ struct dt2815_private {
unsigned int ao_readback[8];
};
-static int dt2815_wait_for_status(struct comedi_device *dev, int status)
+static int dt2815_ao_status(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- int i;
+ unsigned int status;
- for (i = 0; i < 100; i++) {
- if (inb(dev->iobase + DT2815_STATUS) == status)
- break;
- }
- return status;
+ status = inb(dev->iobase + DT2815_STATUS);
+ if (status == context)
+ return 0;
+ return -EBUSY;
}
static int dt2815_ao_insn_read(struct comedi_device *dev,
@@ -98,28 +100,23 @@ static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct dt2815_private *devpriv = dev->private;
int i;
int chan = CR_CHAN(insn->chanspec);
- unsigned int status;
unsigned int lo, hi;
+ int ret;
for (i = 0; i < insn->n; i++) {
lo = ((data[i] & 0x0f) << 4) | (chan << 1) | 0x01;
hi = (data[i] & 0xff0) >> 4;
- status = dt2815_wait_for_status(dev, 0x00);
- if (status != 0) {
- printk(KERN_WARNING "dt2815: failed to write low byte "
- "on %d reason %x\n", chan, status);
- return -EBUSY;
- }
+ ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x00);
+ if (ret)
+ return ret;
outb(lo, dev->iobase + DT2815_DATA);
- status = dt2815_wait_for_status(dev, 0x10);
- if (status != 0x10) {
- printk(KERN_WARNING "dt2815: failed to write high byte "
- "on %d reason %x\n", chan, status);
- return -EBUSY;
- }
+ ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x10);
+ if (ret)
+ return ret;
+
devpriv->ao_readback[chan] = data[i];
}
return i;
@@ -200,12 +197,13 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
unsigned int program;
program = (it->options[4] & 0x3) << 3 | 0x7;
outb(program, dev->iobase + DT2815_DATA);
- printk(KERN_INFO ", program: 0x%x (@t=%d)\n",
- program, i);
+ dev_dbg(dev->class_dev, "program: 0x%x (@t=%d)\n",
+ program, i);
break;
} else if (status != 0x00) {
- printk(KERN_WARNING "dt2815: unexpected status 0x%x "
- "(@t=%d)\n", status, i);
+ dev_dbg(dev->class_dev,
+ "unexpected status 0x%x (@t=%d)\n",
+ status, i);
if (status & 0x60)
outb(0x00, dev->iobase + DT2815_STATUS);
}
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index a01e6b55388..c2a66dcf99f 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -63,9 +63,6 @@ Notes:
#include "comedi_fc.h"
-#define DEBUG
-
-#define DT2821_TIMEOUT 100 /* 500 us */
#define DT2821_SIZE 0x10
/*
@@ -156,55 +153,55 @@ Notes:
static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
4, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-2.5, 2.5),
- RANGE(-1.25, 1.25)
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25)
}
};
static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
4, {
- RANGE(0, 10),
- RANGE(0, 5),
- RANGE(0, 2.5),
- RANGE(0, 1.25)
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
}
};
static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
4, {
- RANGE(-5, 5),
- RANGE(-2.5, 2.5),
- RANGE(-1.25, 1.25),
- RANGE(-0.625, 0.625)
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625)
}
};
static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
4, {
- RANGE(0, 5),
- RANGE(0, 2.5),
- RANGE(0, 1.25),
- RANGE(0, 0.625),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25),
+ UNI_RANGE(0.625)
}
};
static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
4, {
- RANGE(-10, 10),
- RANGE(-1, 1),
- RANGE(-0.1, 0.1),
- RANGE(-0.02, 0.02)
+ BIP_RANGE(10),
+ BIP_RANGE(1),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.02)
}
};
static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
4, {
- RANGE(0, 10),
- RANGE(0, 1),
- RANGE(0, 0.1),
- RANGE(0, 0.02)
+ UNI_RANGE(10),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1),
+ UNI_RANGE(0.02)
}
};
@@ -250,27 +247,6 @@ struct dt282x_private {
* Some useless abstractions
*/
#define chan_to_DAC(a) ((a)&1)
-#define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY)
-#define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE)
-
-/*
- * danger! macro abuse... a is the expression to wait on, and b is
- * the statement(s) to execute if it doesn't happen.
- */
-#define wait_for(a, b) \
- do { \
- int _i; \
- for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \
- if (a) { \
- _i = 0; \
- break; \
- } \
- udelay(5); \
- } \
- if (_i) { \
- b \
- } \
- } while (0)
static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
@@ -308,15 +284,15 @@ static void dt282x_munge(struct comedi_device *dev, unsigned short *buf,
static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
{
struct dt282x_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->write_subdev;
void *ptr;
int size;
int i;
- struct comedi_subdevice *s = &dev->subdevices[1];
outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
if (!s->async->prealloc_buf) {
- printk(KERN_ERR "async->data disappeared. dang!\n");
+ dev_err(dev->class_dev, "no buffer in %s\n", __func__);
return;
}
@@ -329,8 +305,7 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
if (size == 0) {
- printk(KERN_ERR "dt282x: AO underrun\n");
- dt282x_ao_cancel(dev, s);
+ dev_err(dev->class_dev, "AO underrun\n");
s->async->events |= COMEDI_CB_OVERFLOW;
return;
}
@@ -341,16 +316,16 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
{
struct dt282x_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
void *ptr;
int size;
int i;
int ret;
- struct comedi_subdevice *s = &dev->subdevices[0];
outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR);
if (!s->async->prealloc_buf) {
- printk(KERN_ERR "async->data disappeared. dang!\n");
+ dev_err(dev->class_dev, "no buffer in %s\n", __func__);
return;
}
@@ -365,17 +340,16 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
dt282x_munge(dev, ptr, size);
ret = cfc_write_array_to_buffer(s, ptr, size);
if (ret != size) {
- dt282x_ai_cancel(dev, s);
+ s->async->events |= COMEDI_CB_OVERFLOW;
return;
}
devpriv->nread -= size / 2;
if (devpriv->nread < 0) {
- printk(KERN_INFO "dt282x: off by one\n");
+ dev_info(dev->class_dev, "nread off by one\n");
devpriv->nread = 0;
}
if (!devpriv->nread) {
- dt282x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
return;
}
@@ -450,8 +424,8 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct dt282x_private *devpriv = dev->private;
- struct comedi_subdevice *s;
- struct comedi_subdevice *s_ao;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_subdevice *s_ao = dev->write_subdev;
unsigned int supcsr, adcsr, dacsr;
int handled = 0;
@@ -460,8 +434,6 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
return IRQ_HANDLED;
}
- s = &dev->subdevices[0];
- s_ao = &dev->subdevices[1];
adcsr = inw(dev->iobase + DT2821_ADCSR);
dacsr = inw(dev->iobase + DT2821_DACSR);
supcsr = inw(dev->iobase + DT2821_SUPCSR);
@@ -475,22 +447,13 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
if (adcsr & DT2821_ADERR) {
if (devpriv->nread != 0) {
comedi_error(dev, "A/D error");
- dt282x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_ERROR;
}
handled = 1;
}
if (dacsr & DT2821_DAERR) {
-#if 0
- static int warn = 5;
- if (--warn <= 0) {
- disable_irq(dev->irq);
- printk(KERN_INFO "disabling irq\n");
- }
-#endif
comedi_error(dev, "D/A error");
- dt282x_ao_cancel(dev, s_ao);
- s->async->events |= COMEDI_CB_ERROR;
+ s_ao->async->events |= COMEDI_CB_ERROR;
handled = 1;
}
#if 0
@@ -503,7 +466,7 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
if (devpriv->ad_2scomp)
data ^= 1 << (board->adbits - 1);
- ret = comedi_buf_put(s->async, data);
+ ret = comedi_buf_put(s, data);
if (ret == 0)
s->async->events |= COMEDI_CB_OVERFLOW;
@@ -519,9 +482,9 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
handled = 1;
}
#endif
- comedi_event(dev, s);
- /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n",
- adcsr, dacsr, supcsr); */
+ cfc_handle_events(dev, s);
+ cfc_handle_events(dev, s_ao);
+
return IRQ_RETVAL(handled);
}
@@ -542,6 +505,29 @@ static void dt282x_load_changain(struct comedi_device *dev, int n,
outw(n - 1, dev->iobase + DT2821_CHANCSR);
}
+static int dt282x_ai_timeout(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + DT2821_ADCSR);
+ switch (context) {
+ case DT2821_MUXBUSY:
+ if ((status & DT2821_MUXBUSY) == 0)
+ return 0;
+ break;
+ case DT2821_ADDONE:
+ if (status & DT2821_ADDONE)
+ return 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return -EBUSY;
+}
+
/*
* Performs a single A/D conversion.
* - Put channel/gain into channel-gain list
@@ -554,6 +540,7 @@ static int dt282x_ai_insn_read(struct comedi_device *dev,
{
const struct dt282x_board *board = comedi_board(dev);
struct dt282x_private *devpriv = dev->private;
+ int ret;
int i;
/* XXX should we really be enabling the ad clock here? */
@@ -563,13 +550,18 @@ static int dt282x_ai_insn_read(struct comedi_device *dev,
dt282x_load_changain(dev, 1, &insn->chanspec);
outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
- wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
+ ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, DT2821_MUXBUSY);
+ if (ret)
+ return ret;
for (i = 0; i < insn->n; i++) {
outw(devpriv->supcsr | DT2821_STRIG,
dev->iobase + DT2821_SUPCSR);
- wait_for(ad_done(), comedi_error(dev, "timeout\n");
- return -ETIME;);
+
+ ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout,
+ DT2821_ADDONE);
+ if (ret)
+ return ret;
data[i] =
inw(dev->iobase +
@@ -586,7 +578,7 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev,
{
const struct dt282x_board *board = comedi_board(dev);
int err = 0;
- int tmp;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -641,10 +633,9 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
- tmp = cmd->convert_arg;
- dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->convert_arg)
- err++;
+ arg = cmd->convert_arg;
+ dt282x_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
if (err)
return 4;
@@ -658,6 +649,7 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
struct dt282x_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
int timer;
+ int ret;
if (devpriv->usedma == 0) {
comedi_error(dev,
@@ -703,7 +695,9 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR);
outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR);
- wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;);
+ ret = comedi_timeout(dev, s, NULL, dt282x_ai_timeout, DT2821_MUXBUSY);
+ if (ret)
+ return ret;
if (cmd->scan_begin_src == TRIG_FOLLOW) {
outw(devpriv->supcsr | DT2821_STRIG,
@@ -830,7 +824,7 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
int err = 0;
- int tmp;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -857,7 +851,7 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
- err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg, 2);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
if (cmd->stop_src == TRIG_COUNT) {
/* any count is allowed */
@@ -870,10 +864,9 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
- tmp = cmd->scan_begin_arg;
- dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->scan_begin_arg)
- err++;
+ arg = cmd->scan_begin_arg;
+ dt282x_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
if (err)
return 4;
@@ -883,18 +876,20 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev,
}
static int dt282x_ao_inttrig(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int x)
+ struct comedi_subdevice *s,
+ unsigned int trig_num)
{
struct dt282x_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
int size;
- if (x != 0)
+ if (trig_num != cmd->start_src)
return -EINVAL;
size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf,
devpriv->dma_maxsize);
if (size == 0) {
- printk(KERN_ERR "dt282x: AO underrun\n");
+ dev_err(dev->class_dev, "AO underrun\n");
return -EPIPE;
}
prep_ao_dma(dev, 0, size);
@@ -902,7 +897,7 @@ static int dt282x_ao_inttrig(struct comedi_device *dev,
size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf,
devpriv->dma_maxsize);
if (size == 0) {
- printk(KERN_ERR "dt282x: AO underrun\n");
+ dev_err(dev->class_dev, "AO underrun\n");
return -EPIPE;
}
prep_ao_dma(dev, 1, size);
@@ -1062,10 +1057,8 @@ static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
devpriv->usedma = 0;
- if (!dma1 && !dma2) {
- printk(KERN_ERR " (no dma)");
+ if (!dma1 && !dma2)
return 0;
- }
if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
return -EINVAL;
@@ -1090,12 +1083,8 @@ static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
devpriv->dma_maxsize = PAGE_SIZE;
devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
- if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
- printk(KERN_ERR " can't get DMA memory");
+ if (!devpriv->dma[0].buf || !devpriv->dma[1].buf)
return -ENOMEM;
- }
-
- printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
devpriv->usedma = 1;
@@ -1120,9 +1109,9 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct dt282x_board *board = comedi_board(dev);
struct dt282x_private *devpriv;
- int i, irq;
- int ret;
struct comedi_subdevice *s;
+ int ret;
+ int i;
ret = comedi_request_region(dev, it->options[0], DT2821_SIZE);
if (ret)
@@ -1130,14 +1119,6 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
i = inw(dev->iobase + DT2821_ADCSR);
-#ifdef DEBUG
- printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x",
- inw(dev->iobase + DT2821_ADCSR),
- inw(dev->iobase + DT2821_CHANCSR),
- inw(dev->iobase + DT2821_DACSR),
- inw(dev->iobase + DT2821_SUPCSR),
- inw(dev->iobase + DT2821_TMRCTR));
-#endif
if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK)
!= DT2821_ADCSR_VAL) ||
@@ -1149,58 +1130,28 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
!= DT2821_SUPCSR_VAL) ||
((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK)
!= DT2821_TMRCTR_VAL)) {
- printk(KERN_ERR " board not found");
+ dev_err(dev->class_dev, "board not found\n");
return -EIO;
}
/* should do board test */
- irq = it->options[opt_irq];
-#if 0
- if (irq < 0) {
- unsigned long flags;
- int irqs;
-
- save_flags(flags);
- sti();
- irqs = probe_irq_on();
-
- /* trigger interrupt */
-
- udelay(100);
-
- irq = probe_irq_off(irqs);
- restore_flags(flags);
- if (0 /* error */)
- printk(KERN_ERR " error probing irq (bad)");
- }
-#endif
- if (irq > 0) {
- printk(KERN_INFO " ( irq = %d )", irq);
- ret = request_irq(irq, dt282x_interrupt, 0,
+ if (it->options[opt_irq] > 0) {
+ ret = request_irq(it->options[opt_irq], dt282x_interrupt, 0,
dev->board_name, dev);
- if (ret < 0) {
- printk(KERN_ERR " failed to get irq\n");
- return -EIO;
- }
- dev->irq = irq;
- } else if (irq == 0) {
- printk(KERN_INFO " (no irq)");
- } else {
-#if 0
- printk(KERN_INFO " (probe returned multiple irqs--bad)");
-#else
- printk(KERN_INFO " (irq probe not implemented)");
-#endif
+ if (ret == 0)
+ dev->irq = it->options[opt_irq];
}
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- ret = dt282x_grab_dma(dev, it->options[opt_dma1],
- it->options[opt_dma2]);
- if (ret < 0)
- return ret;
+ if (dev->irq) {
+ ret = dt282x_grab_dma(dev, it->options[opt_dma1],
+ it->options[opt_dma2]);
+ if (ret < 0)
+ return ret;
+ }
ret = comedi_alloc_subdevices(dev, 3);
if (ret)
@@ -1208,22 +1159,25 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s = &dev->subdevices[0];
- dev->read_subdev = s;
/* ai subdevice */
s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
+ s->subdev_flags = SDF_READABLE |
((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
s->n_chan =
(it->options[opt_diff]) ? board->adchan_di : board->adchan_se;
s->insn_read = dt282x_ai_insn_read;
- s->do_cmdtest = dt282x_ai_cmdtest;
- s->do_cmd = dt282x_ai_cmd;
- s->cancel = dt282x_ai_cancel;
s->maxdata = (1 << board->adbits) - 1;
- s->len_chanlist = 16;
s->range_table =
opt_ai_range_lkup(board->ispgl, it->options[opt_ai_range]);
devpriv->ad_2scomp = it->options[opt_ai_twos];
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = 16;
+ s->do_cmdtest = dt282x_ai_cmdtest;
+ s->do_cmd = dt282x_ai_cmd;
+ s->cancel = dt282x_ai_cancel;
+ }
s = &dev->subdevices[1];
@@ -1231,15 +1185,10 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (s->n_chan) {
/* ao subsystem */
s->type = COMEDI_SUBD_AO;
- dev->write_subdev = s;
- s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE;
+ s->subdev_flags = SDF_WRITABLE;
s->insn_read = dt282x_ao_insn_read;
s->insn_write = dt282x_ao_insn_write;
- s->do_cmdtest = dt282x_ao_cmdtest;
- s->do_cmd = dt282x_ao_cmd;
- s->cancel = dt282x_ao_cancel;
s->maxdata = (1 << board->dabits) - 1;
- s->len_chanlist = 2;
s->range_table_list = devpriv->darangelist;
devpriv->darangelist[0] =
opt_ao_range_lkup(it->options[opt_ao0_range]);
@@ -1247,6 +1196,14 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
opt_ao_range_lkup(it->options[opt_ao1_range]);
devpriv->da0_2scomp = it->options[opt_ao0_twos];
devpriv->da1_2scomp = it->options[opt_ao1_twos];
+ if (dev->irq) {
+ dev->write_subdev = s;
+ s->subdev_flags |= SDF_CMD_WRITE;
+ s->len_chanlist = 2;
+ s->do_cmdtest = dt282x_ao_cmdtest;
+ s->do_cmd = dt282x_ao_cmd;
+ s->cancel = dt282x_ao_cancel;
+ }
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -1261,8 +1218,6 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->maxdata = 1;
s->range_table = &range_digital;
- printk(KERN_INFO "\n");
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index 292226eeff9..4ab4de00592 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -48,8 +48,6 @@ AO commands are not supported.
you the docs without one, also.
*/
-#define DEBUG 1
-
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
@@ -253,24 +251,6 @@ struct dt3k_private {
unsigned int ai_rear;
};
-#ifdef DEBUG
-static char *intr_flags[] = {
- "AdFull", "AdSwError", "AdHwError", "DaEmpty",
- "DaSwError", "DaHwError", "CtDone", "CmDone",
-};
-
-static void debug_intr_flags(unsigned int flags)
-{
- int i;
- printk(KERN_DEBUG "dt3k: intr_flags:");
- for (i = 0; i < 8; i++) {
- if (flags & (1 << i))
- printk(KERN_CONT " %s", intr_flags[i]);
- }
- printk(KERN_CONT "\n");
-}
-#endif
-
#define TIMEOUT 100
static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
@@ -342,7 +322,7 @@ static void dt3k_ai_empty_fifo(struct comedi_device *dev,
for (i = 0; i < count; i++) {
data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
- comedi_buf_put(s->async, data);
+ comedi_buf_put(s, data);
rear++;
if (rear >= AI_FIFO_DEPTH)
rear = 0;
@@ -372,17 +352,13 @@ static irqreturn_t dt3k_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct dt3k_private *devpriv = dev->private;
- struct comedi_subdevice *s;
+ struct comedi_subdevice *s = dev->read_subdev;
unsigned int status;
if (!dev->attached)
return IRQ_NONE;
- s = &dev->subdevices[0];
status = readw(devpriv->io_addr + DPR_Intr_Flag);
-#ifdef DEBUG
- debug_intr_flags(status);
-#endif
if (status & DT3000_ADFULL) {
dt3k_ai_empty_fifo(dev, s);
@@ -393,12 +369,10 @@ static irqreturn_t dt3k_interrupt(int irq, void *d)
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
debug_n_ints++;
- if (debug_n_ints >= 10) {
- dt3k_ai_cancel(dev, s);
+ if (debug_n_ints >= 10)
s->async->events |= COMEDI_CB_EOA;
- }
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
@@ -442,7 +416,7 @@ static int dt3k_ai_cmdtest(struct comedi_device *dev,
{
const struct dt3k_boardtype *this_board = comedi_board(dev);
int err = 0;
- int tmp;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -492,25 +466,20 @@ static int dt3k_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
- dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->scan_begin_arg)
- err++;
+ arg = cmd->scan_begin_arg;
+ dt3k_ns_to_timer(100, &arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
- dt3k_ns_to_timer(50, &cmd->convert_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->convert_arg)
- err++;
- if (cmd->scan_begin_src == TRIG_TIMER &&
- cmd->scan_begin_arg <
- cmd->convert_arg * cmd->scan_end_arg) {
- cmd->scan_begin_arg =
- cmd->convert_arg * cmd->scan_end_arg;
- err++;
+ arg = cmd->convert_arg;
+ dt3k_ns_to_timer(50, &arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
+
+ if (cmd->scan_begin_src == TRIG_TIMER) {
+ arg = cmd->convert_arg * cmd->scan_end_arg;
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ arg);
}
}
@@ -725,29 +694,33 @@ static int dt3000_auto_attach(struct comedi_device *dev,
if (!devpriv->io_addr)
return -ENOMEM;
- ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
- dev->board_name, dev);
- if (ret)
- return ret;
- dev->irq = pcidev->irq;
+ if (pcidev->irq) {
+ ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = pcidev->irq;
+ }
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
return ret;
s = &dev->subdevices[0];
- dev->read_subdev = s;
/* ai subdevice */
s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
s->n_chan = this_board->adchan;
s->insn_read = dt3k_ai_insn;
s->maxdata = (1 << this_board->adbits) - 1;
- s->len_chanlist = 512;
s->range_table = &range_dt3000_ai; /* XXX */
- s->do_cmd = dt3k_ai_cmd;
- s->do_cmdtest = dt3k_ai_cmdtest;
- s->cancel = dt3k_ai_cancel;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = 512;
+ s->do_cmd = dt3k_ai_cmd;
+ s->do_cmdtest = dt3k_ai_cmdtest;
+ s->cancel = dt3k_ai_cancel;
+ }
s = &dev->subdevices[1];
/* ao subsystem */
@@ -787,8 +760,6 @@ static int dt3000_auto_attach(struct comedi_device *dev,
s->type = COMEDI_SUBD_PROC;
#endif
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
@@ -818,7 +789,7 @@ static int dt3000_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = {
+static const struct pci_device_id dt3000_pci_table[] = {
{ PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
{ PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
{ PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index 73af600c172..b3aeb6fb2ad 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -41,7 +41,6 @@ for my needs.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index f2a9f1c2f3b..e5593f8c740 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -42,11 +42,12 @@
#define READ_TIMEOUT 50
-static const struct comedi_lrange range_pci1050_ai = { 3, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- UNI_RANGE(10)
- }
+static const struct comedi_lrange range_pci1050_ai = {
+ 3, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ UNI_RANGE(10)
+ }
};
static const char range_codes_pci1050_ai[] = { 0x00, 0x10, 0x30 };
@@ -56,18 +57,27 @@ struct dyna_pci10xx_private {
unsigned long BADR3;
};
-/******************************************************************************/
-/************************** READ WRITE FUNCTIONS ******************************/
-/******************************************************************************/
+static int dyna_pci10xx_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw_p(dev->iobase);
+ if (status & (1 << 15))
+ return 0;
+ return -EBUSY;
+}
-/* analog input callback */
static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct dyna_pci10xx_private *devpriv = dev->private;
- int n, counter;
+ int n;
u16 d = 0;
+ int ret = 0;
unsigned int chan, range;
/* get the channel number and range */
@@ -81,19 +91,13 @@ static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev,
smp_mb();
outw_p(0x0000 + range + chan, dev->iobase + 2);
udelay(10);
+
+ ret = comedi_timeout(dev, s, insn, dyna_pci10xx_ai_eoc, 0);
+ if (ret)
+ break;
+
/* read data */
- for (counter = 0; counter < READ_TIMEOUT; counter++) {
- d = inw_p(dev->iobase);
-
- /* check if read is successful if the EOC bit is set */
- if (d & (1 << 15))
- goto conv_finish;
- }
- data[n] = 0;
- printk(KERN_DEBUG "comedi: dyna_pci10xx: "
- "timeout reading analog input\n");
- continue;
-conv_finish:
+ d = inw_p(dev->iobase);
/* mask the first 4 bits - EOC bits */
d &= 0x0FFF;
data[n] = d;
@@ -101,7 +105,7 @@ conv_finish:
mutex_unlock(&devpriv->mutex);
/* return the number of samples read/written */
- return n;
+ return ret ? ret : n;
}
/* analog output callback */
@@ -232,8 +236,6 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev,
s->state = 0;
s->insn_bits = dyna_pci10xx_do_insn_bits;
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
@@ -260,7 +262,7 @@ static int dyna_pci10xx_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = {
+static const struct pci_device_id dyna_pci10xx_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_PLX, 0x1050) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index e3ff4c43897..4e410f3b0e2 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -1,110 +1,128 @@
/*
- comedi/drivers/fl512.c
- Anders Gnistrup <ex18@kalman.iau.dtu.dk>
-*/
+ * fl512.c
+ * Anders Gnistrup <ex18@kalman.iau.dtu.dk>
+ *
+ * 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.
+ */
/*
-Driver: fl512
-Description: unknown
-Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk>
-Devices: [unknown] FL512 (fl512)
-Status: unknown
-
-Digital I/O is not supported.
-
-Configuration options:
- [0] - I/O port base address
-*/
-
-#define DEBUG 0
+ * Driver: fl512
+ * Description: unknown
+ * Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk>
+ * Devices: [unknown] FL512 (fl512)
+ * Status: unknown
+ *
+ * Digital I/O is not supported.
+ *
+ * Configuration options:
+ * [0] - I/O port base address
+ */
#include <linux/module.h>
#include "../comedidev.h"
#include <linux/delay.h>
-#define FL512_SIZE 16 /* the size of the used memory */
+/*
+ * Register I/O map
+ */
+#define FL512_AI_LSB_REG 0x02
+#define FL512_AI_MSB_REG 0x03
+#define FL512_AI_MUX_REG 0x02
+#define FL512_AI_START_CONV_REG 0x03
+#define FL512_AO_DATA_REG(x) (0x04 + ((x) * 2))
+#define FL512_AO_TRIG_REG(x) (0x04 + ((x) * 2))
+
struct fl512_private {
unsigned short ao_readback[2];
};
-static const struct comedi_lrange range_fl512 = { 4, {
- BIP_RANGE(0.5),
- BIP_RANGE(1),
- BIP_RANGE(5),
- BIP_RANGE(10),
- UNI_RANGE(1),
- UNI_RANGE(5),
- UNI_RANGE(10),
- }
+static const struct comedi_lrange range_fl512 = {
+ 4, {
+ BIP_RANGE(0.5),
+ BIP_RANGE(1),
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ UNI_RANGE(1),
+ UNI_RANGE(5),
+ UNI_RANGE(10)
+ }
};
-/*
- * fl512_ai_insn : this is the analog input function
- */
-static int fl512_ai_insn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
+static int fl512_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int n;
- unsigned int lo_byte, hi_byte;
- char chan = CR_CHAN(insn->chanspec);
- unsigned long iobase = dev->iobase;
-
- for (n = 0; n < insn->n; n++) { /* sample n times on selected channel */
- /* XXX probably can move next step out of for() loop -- will
- * make AI a little bit faster. */
- outb(chan, iobase + 2); /* select chan */
- outb(0, iobase + 3); /* start conversion */
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
+ int i;
+
+ outb(chan, dev->iobase + FL512_AI_MUX_REG);
+
+ for (i = 0; i < insn->n; i++) {
+ outb(0, dev->iobase + FL512_AI_START_CONV_REG);
+
/* XXX should test "done" flag instead of delay */
- udelay(30); /* sleep 30 usec */
- lo_byte = inb(iobase + 2); /* low 8 byte */
- hi_byte = inb(iobase + 3) & 0xf; /* high 4 bit and mask */
- data[n] = lo_byte + (hi_byte << 8);
+ udelay(30);
+
+ val = inb(dev->iobase + FL512_AI_LSB_REG);
+ val |= (inb(dev->iobase + FL512_AI_MSB_REG) << 8);
+ val &= s->maxdata;
+
+ data[i] = val;
}
- return n;
+
+ return insn->n;
}
-/*
- * fl512_ao_insn : used to write to a DA port n times
- */
-static int fl512_ao_insn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
+static int fl512_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct fl512_private *devpriv = dev->private;
- int n;
- int chan = CR_CHAN(insn->chanspec); /* get chan to write */
- unsigned long iobase = dev->iobase; /* get base address */
-
- for (n = 0; n < insn->n; n++) { /* write n data set */
- /* write low byte */
- outb(data[n] & 0x0ff, iobase + 4 + 2 * chan);
- /* write high byte */
- outb((data[n] & 0xf00) >> 8, iobase + 4 + 2 * chan);
- inb(iobase + 4 + 2 * chan); /* trig */
-
- devpriv->ao_readback[chan] = data[n];
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = devpriv->ao_readback[chan];
+ int i;
+
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+
+ /* write LSB, MSB then trigger conversion */
+ outb(val & 0x0ff, dev->iobase + FL512_AO_DATA_REG(chan));
+ outb((val >> 8) & 0xf, dev->iobase + FL512_AO_DATA_REG(chan));
+ inb(dev->iobase + FL512_AO_TRIG_REG(chan));
}
- return n;
+ devpriv->ao_readback[chan] = val;
+
+ return insn->n;
}
-/*
- * fl512_ao_insn_readback : used to read previous values written to
- * DA port
- */
-static int fl512_ao_insn_readback(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int fl512_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct fl512_private *devpriv = dev->private;
- int n;
- int chan = CR_CHAN(insn->chanspec);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
- for (n = 0; n < insn->n; n++)
- data[n] = devpriv->ao_readback[chan];
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
- return n;
+ return insn->n;
}
static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -113,7 +131,7 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
int ret;
- ret = comedi_request_region(dev, it->options[0], FL512_SIZE);
+ ret = comedi_request_region(dev, it->options[0], 0x10);
if (ret)
return ret;
@@ -125,42 +143,26 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- /*
- * this if the definitions of the supdevices, 2 have been defined
- */
- /* Analog indput */
+ /* Analog Input subdevice */
s = &dev->subdevices[0];
- /* define subdevice as Analog In */
- s->type = COMEDI_SUBD_AI;
- /* you can read it from userspace */
- s->subdev_flags = SDF_READABLE | SDF_GROUND;
- /* Number of Analog input channels */
- s->n_chan = 16;
- /* accept only 12 bits of data */
- s->maxdata = 0x0fff;
- /* device use one of the ranges */
- s->range_table = &range_fl512;
- /* function to call when read AD */
- s->insn_read = fl512_ai_insn;
-
- /* Analog output */
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND;
+ s->n_chan = 16;
+ s->maxdata = 0x0fff;
+ s->range_table = &range_fl512;
+ s->insn_read = fl512_ai_insn_read;
+
+ /* Analog Output subdevice */
s = &dev->subdevices[1];
- /* define subdevice as Analog OUT */
- s->type = COMEDI_SUBD_AO;
- /* you can write it from userspace */
- s->subdev_flags = SDF_WRITABLE;
- /* Number of Analog output channels */
- s->n_chan = 2;
- /* accept only 12 bits of data */
- s->maxdata = 0x0fff;
- /* device use one of the ranges */
- s->range_table = &range_fl512;
- /* function to call when write DA */
- s->insn_write = fl512_ao_insn;
- /* function to call when reading DA */
- s->insn_read = fl512_ao_insn_readback;
-
- return 1;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 2;
+ s->maxdata = 0x0fff;
+ s->range_table = &range_fl512;
+ s->insn_write = fl512_ao_insn_write;
+ s->insn_read = fl512_ao_insn_read;
+
+ return 0;
}
static struct comedi_driver fl512_driver = {
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index 559bf558353..22333c1ad88 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -1,24 +1,24 @@
/*
- comedi/drivers/gsc_hpdi.c
- This is a driver for the General Standards Corporation High
- Speed Parallel Digital Interface rs485 boards.
-
- Author: Frank Mori Hess <fmhess@users.sourceforge.net>
- Copyright (C) 2003 Coherent Imaging Systems
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1997-8 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.
-*/
+ * gsc_hpdi.c
+ * Comedi driver the General Standards Corporation
+ * High Speed Parallel Digital Interface rs485 boards.
+ *
+ * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Copyright (C) 2003 Coherent Imaging Systems
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-8 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: gsc_hpdi
@@ -40,8 +40,6 @@
* support could be added to this driver.
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
@@ -52,158 +50,105 @@
#include "plx9080.h"
#include "comedi_fc.h"
-static void abort_dma(struct comedi_device *dev, unsigned int channel);
-static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static irqreturn_t handle_interrupt(int irq, void *d);
-static int dio_config_block_size(struct comedi_device *dev, unsigned int *data);
-
-#undef HPDI_DEBUG /* disable debugging messages */
-/* #define HPDI_DEBUG enable debugging code */
-
-#ifdef HPDI_DEBUG
-#define DEBUG_PRINT(format, args...) pr_debug(format , ## args)
-#else
-#define DEBUG_PRINT(format, args...) no_printk(pr_fmt(format), ## args)
-#endif
-
-#define TIMER_BASE 50 /* 20MHz master clock */
-#define DMA_BUFFER_SIZE 0x10000
-#define NUM_DMA_BUFFERS 4
-#define NUM_DMA_DESCRIPTORS 256
-
-enum hpdi_registers {
- FIRMWARE_REV_REG = 0x0,
- BOARD_CONTROL_REG = 0x4,
- BOARD_STATUS_REG = 0x8,
- TX_PROG_ALMOST_REG = 0xc,
- RX_PROG_ALMOST_REG = 0x10,
- FEATURES_REG = 0x14,
- FIFO_REG = 0x18,
- TX_STATUS_COUNT_REG = 0x1c,
- TX_LINE_VALID_COUNT_REG = 0x20,
- TX_LINE_INVALID_COUNT_REG = 0x24,
- RX_STATUS_COUNT_REG = 0x28,
- RX_LINE_COUNT_REG = 0x2c,
- INTERRUPT_CONTROL_REG = 0x30,
- INTERRUPT_STATUS_REG = 0x34,
- TX_CLOCK_DIVIDER_REG = 0x38,
- TX_FIFO_SIZE_REG = 0x40,
- RX_FIFO_SIZE_REG = 0x44,
- TX_FIFO_WORDS_REG = 0x48,
- RX_FIFO_WORDS_REG = 0x4c,
- INTERRUPT_EDGE_LEVEL_REG = 0x50,
- INTERRUPT_POLARITY_REG = 0x54,
-};
-
-/* bit definitions */
-
-enum firmware_revision_bits {
- FEATURES_REG_PRESENT_BIT = 0x8000,
-};
-
-enum board_control_bits {
- BOARD_RESET_BIT = 0x1, /* wait 10usec before accessing fifos */
- TX_FIFO_RESET_BIT = 0x2,
- RX_FIFO_RESET_BIT = 0x4,
- TX_ENABLE_BIT = 0x10,
- RX_ENABLE_BIT = 0x20,
- DEMAND_DMA_DIRECTION_TX_BIT = 0x40,
- /* for ch 0, ch 1 can only transmit (when present) */
- LINE_VALID_ON_STATUS_VALID_BIT = 0x80,
- START_TX_BIT = 0x10,
- CABLE_THROTTLE_ENABLE_BIT = 0x20,
- TEST_MODE_ENABLE_BIT = 0x80000000,
-};
-
-enum board_status_bits {
- COMMAND_LINE_STATUS_MASK = 0x7f,
- TX_IN_PROGRESS_BIT = 0x80,
- TX_NOT_EMPTY_BIT = 0x100,
- TX_NOT_ALMOST_EMPTY_BIT = 0x200,
- TX_NOT_ALMOST_FULL_BIT = 0x400,
- TX_NOT_FULL_BIT = 0x800,
- RX_NOT_EMPTY_BIT = 0x1000,
- RX_NOT_ALMOST_EMPTY_BIT = 0x2000,
- RX_NOT_ALMOST_FULL_BIT = 0x4000,
- RX_NOT_FULL_BIT = 0x8000,
- BOARD_JUMPER0_INSTALLED_BIT = 0x10000,
- BOARD_JUMPER1_INSTALLED_BIT = 0x20000,
- TX_OVERRUN_BIT = 0x200000,
- RX_UNDERRUN_BIT = 0x400000,
- RX_OVERRUN_BIT = 0x800000,
-};
-
-static uint32_t almost_full_bits(unsigned int num_words)
-{
- /* XXX need to add or subtract one? */
- return (num_words << 16) & 0xff0000;
-}
-
-static uint32_t almost_empty_bits(unsigned int num_words)
-{
- return num_words & 0xffff;
-}
-
-enum features_bits {
- FIFO_SIZE_PRESENT_BIT = 0x1,
- FIFO_WORDS_PRESENT_BIT = 0x2,
- LEVEL_EDGE_INTERRUPTS_PRESENT_BIT = 0x4,
- GPIO_SUPPORTED_BIT = 0x8,
- PLX_DMA_CH1_SUPPORTED_BIT = 0x10,
- OVERRUN_UNDERRUN_SUPPORTED_BIT = 0x20,
-};
-
-enum interrupt_sources {
- FRAME_VALID_START_INTR = 0,
- FRAME_VALID_END_INTR = 1,
- TX_FIFO_EMPTY_INTR = 8,
- TX_FIFO_ALMOST_EMPTY_INTR = 9,
- TX_FIFO_ALMOST_FULL_INTR = 10,
- TX_FIFO_FULL_INTR = 11,
- RX_EMPTY_INTR = 12,
- RX_ALMOST_EMPTY_INTR = 13,
- RX_ALMOST_FULL_INTR = 14,
- RX_FULL_INTR = 15,
-};
-
-static uint32_t intr_bit(int interrupt_source)
-{
- return 0x1 << interrupt_source;
-}
-
-static unsigned int fifo_size(uint32_t fifo_size_bits)
-{
- return fifo_size_bits & 0xfffff;
-}
+/*
+ * PCI BAR2 Register map (devpriv->mmio)
+ */
+#define FIRMWARE_REV_REG 0x00
+#define FEATURES_REG_PRESENT_BIT (1 << 15)
+#define BOARD_CONTROL_REG 0x04
+#define BOARD_RESET_BIT (1 << 0)
+#define TX_FIFO_RESET_BIT (1 << 1)
+#define RX_FIFO_RESET_BIT (1 << 2)
+#define TX_ENABLE_BIT (1 << 4)
+#define RX_ENABLE_BIT (1 << 5)
+#define DEMAND_DMA_DIRECTION_TX_BIT (1 << 6) /* ch 0 only */
+#define LINE_VALID_ON_STATUS_VALID_BIT (1 << 7)
+#define START_TX_BIT (1 << 8)
+#define CABLE_THROTTLE_ENABLE_BIT (1 << 9)
+#define TEST_MODE_ENABLE_BIT (1 << 31)
+#define BOARD_STATUS_REG 0x08
+#define COMMAND_LINE_STATUS_MASK (0x7f << 0)
+#define TX_IN_PROGRESS_BIT (1 << 7)
+#define TX_NOT_EMPTY_BIT (1 << 8)
+#define TX_NOT_ALMOST_EMPTY_BIT (1 << 9)
+#define TX_NOT_ALMOST_FULL_BIT (1 << 10)
+#define TX_NOT_FULL_BIT (1 << 11)
+#define RX_NOT_EMPTY_BIT (1 << 12)
+#define RX_NOT_ALMOST_EMPTY_BIT (1 << 13)
+#define RX_NOT_ALMOST_FULL_BIT (1 << 14)
+#define RX_NOT_FULL_BIT (1 << 15)
+#define BOARD_JUMPER0_INSTALLED_BIT (1 << 16)
+#define BOARD_JUMPER1_INSTALLED_BIT (1 << 17)
+#define TX_OVERRUN_BIT (1 << 21)
+#define RX_UNDERRUN_BIT (1 << 22)
+#define RX_OVERRUN_BIT (1 << 23)
+#define TX_PROG_ALMOST_REG 0x0c
+#define RX_PROG_ALMOST_REG 0x10
+#define ALMOST_EMPTY_BITS(x) (((x) & 0xffff) << 0)
+#define ALMOST_FULL_BITS(x) (((x) & 0xff) << 16)
+#define FEATURES_REG 0x14
+#define FIFO_SIZE_PRESENT_BIT (1 << 0)
+#define FIFO_WORDS_PRESENT_BIT (1 << 1)
+#define LEVEL_EDGE_INTERRUPTS_PRESENT_BIT (1 << 2)
+#define GPIO_SUPPORTED_BIT (1 << 3)
+#define PLX_DMA_CH1_SUPPORTED_BIT (1 << 4)
+#define OVERRUN_UNDERRUN_SUPPORTED_BIT (1 << 5)
+#define FIFO_REG 0x18
+#define TX_STATUS_COUNT_REG 0x1c
+#define TX_LINE_VALID_COUNT_REG 0x20,
+#define TX_LINE_INVALID_COUNT_REG 0x24
+#define RX_STATUS_COUNT_REG 0x28
+#define RX_LINE_COUNT_REG 0x2c
+#define INTERRUPT_CONTROL_REG 0x30
+#define FRAME_VALID_START_INTR (1 << 0)
+#define FRAME_VALID_END_INTR (1 << 1)
+#define TX_FIFO_EMPTY_INTR (1 << 8)
+#define TX_FIFO_ALMOST_EMPTY_INTR (1 << 9)
+#define TX_FIFO_ALMOST_FULL_INTR (1 << 10)
+#define TX_FIFO_FULL_INTR (1 << 11)
+#define RX_EMPTY_INTR (1 << 12)
+#define RX_ALMOST_EMPTY_INTR (1 << 13)
+#define RX_ALMOST_FULL_INTR (1 << 14)
+#define RX_FULL_INTR (1 << 15)
+#define INTERRUPT_STATUS_REG 0x34
+#define TX_CLOCK_DIVIDER_REG 0x38
+#define TX_FIFO_SIZE_REG 0x40
+#define RX_FIFO_SIZE_REG 0x44
+#define FIFO_SIZE_MASK (0xfffff << 0)
+#define TX_FIFO_WORDS_REG 0x48
+#define RX_FIFO_WORDS_REG 0x4c
+#define INTERRUPT_EDGE_LEVEL_REG 0x50
+#define INTERRUPT_POLARITY_REG 0x54
+
+#define TIMER_BASE 50 /* 20MHz master clock */
+#define DMA_BUFFER_SIZE 0x10000
+#define NUM_DMA_BUFFERS 4
+#define NUM_DMA_DESCRIPTORS 256
struct hpdi_board {
- const char *name; /* board name */
- int device_id; /* pci device id */
- int subdevice_id; /* pci subdevice id */
+ const char *name;
+ int device_id;
+ int subdevice_id;
};
static const struct hpdi_board hpdi_boards[] = {
{
- .name = "pci-hpdi32",
- .device_id = PCI_DEVICE_ID_PLX_9080,
- .subdevice_id = 0x2400,
+ .name = "pci-hpdi32",
+ .device_id = PCI_DEVICE_ID_PLX_9080,
+ .subdevice_id = 0x2400,
},
#if 0
{
- .name = "pxi-hpdi32",
- .device_id = 0x9656,
- .subdevice_id = 0x2705,
+ .name = "pxi-hpdi32",
+ .device_id = 0x9656,
+ .subdevice_id = 0x2705,
},
#endif
};
struct hpdi_private {
- /* base addresses (ioremapped) */
- void __iomem *plx9080_iobase;
- void __iomem *hpdi_iobase;
+ void __iomem *plx9080_mmio;
+ void __iomem *mmio;
uint32_t *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */
/* physical addresses of dma buffers */
dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS];
@@ -216,26 +161,346 @@ struct hpdi_private {
/* pointer to start of buffers indexed by descriptor */
uint32_t *desc_dio_buffer[NUM_DMA_DESCRIPTORS];
/* index of the dma descriptor that is currently being used */
- volatile unsigned int dma_desc_index;
+ unsigned int dma_desc_index;
unsigned int tx_fifo_size;
unsigned int rx_fifo_size;
- volatile unsigned long dio_count;
- /* software copies of values written to hpdi registers */
- volatile uint32_t bits[24];
+ unsigned long dio_count;
/* number of bytes at which to generate COMEDI_CB_BLOCK events */
- volatile unsigned int block_size;
+ unsigned int block_size;
};
-static int dio_config_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static void gsc_hpdi_drain_dma(struct comedi_device *dev, unsigned int channel)
+{
+ struct hpdi_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int idx;
+ unsigned int start;
+ unsigned int desc;
+ unsigned int size;
+ unsigned int next;
+
+ if (channel)
+ next = readl(devpriv->plx9080_mmio + PLX_DMA1_PCI_ADDRESS_REG);
+ else
+ next = readl(devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG);
+
+ idx = devpriv->dma_desc_index;
+ start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr);
+ /* loop until we have read all the full buffers */
+ for (desc = 0; (next < start || next >= start + devpriv->block_size) &&
+ desc < devpriv->num_dma_descriptors; desc++) {
+ /* transfer data from dma buffer to comedi buffer */
+ size = devpriv->block_size / sizeof(uint32_t);
+ if (cmd->stop_src == TRIG_COUNT) {
+ if (size > devpriv->dio_count)
+ size = devpriv->dio_count;
+ devpriv->dio_count -= size;
+ }
+ cfc_write_array_to_buffer(s, devpriv->desc_dio_buffer[idx],
+ size * sizeof(uint32_t));
+ idx++;
+ idx %= devpriv->num_dma_descriptors;
+ start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr);
+
+ devpriv->dma_desc_index = idx;
+ }
+ /* XXX check for buffer overrun somehow */
+}
+
+static irqreturn_t gsc_hpdi_interrupt(int irq, void *d)
+{
+ struct comedi_device *dev = d;
+ struct hpdi_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_async *async = s->async;
+ uint32_t hpdi_intr_status, hpdi_board_status;
+ uint32_t plx_status;
+ uint32_t plx_bits;
+ uint8_t dma0_status, dma1_status;
+ unsigned long flags;
+
+ if (!dev->attached)
+ return IRQ_NONE;
+
+ plx_status = readl(devpriv->plx9080_mmio + PLX_INTRCS_REG);
+ if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0)
+ return IRQ_NONE;
+
+ hpdi_intr_status = readl(devpriv->mmio + INTERRUPT_STATUS_REG);
+ hpdi_board_status = readl(devpriv->mmio + BOARD_STATUS_REG);
+
+ if (hpdi_intr_status)
+ writel(hpdi_intr_status, devpriv->mmio + INTERRUPT_STATUS_REG);
+
+ /* spin lock makes sure no one else changes plx dma control reg */
+ spin_lock_irqsave(&dev->spinlock, flags);
+ dma0_status = readb(devpriv->plx9080_mmio + PLX_DMA0_CS_REG);
+ if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */
+ writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT,
+ devpriv->plx9080_mmio + PLX_DMA0_CS_REG);
+
+ if (dma0_status & PLX_DMA_EN_BIT)
+ gsc_hpdi_drain_dma(dev, 0);
+ }
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+
+ /* spin lock makes sure no one else changes plx dma control reg */
+ spin_lock_irqsave(&dev->spinlock, flags);
+ dma1_status = readb(devpriv->plx9080_mmio + PLX_DMA1_CS_REG);
+ if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */
+ writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT,
+ devpriv->plx9080_mmio + PLX_DMA1_CS_REG);
+ }
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+
+ /* clear possible plx9080 interrupt sources */
+ if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */
+ plx_bits = readl(devpriv->plx9080_mmio + PLX_DBR_OUT_REG);
+ writel(plx_bits, devpriv->plx9080_mmio + PLX_DBR_OUT_REG);
+ }
+
+ if (hpdi_board_status & RX_OVERRUN_BIT) {
+ dev_err(dev->class_dev, "rx fifo overrun\n");
+ async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ }
+
+ if (hpdi_board_status & RX_UNDERRUN_BIT) {
+ dev_err(dev->class_dev, "rx fifo underrun\n");
+ async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ }
+
+ if (devpriv->dio_count == 0)
+ async->events |= COMEDI_CB_EOA;
+
+ cfc_handle_events(dev, s);
+
+ return IRQ_HANDLED;
+}
+
+static void gsc_hpdi_abort_dma(struct comedi_device *dev, unsigned int channel)
+{
+ struct hpdi_private *devpriv = dev->private;
+ unsigned long flags;
+
+ /* spinlock for plx dma control/status reg */
+ spin_lock_irqsave(&dev->spinlock, flags);
+
+ plx9080_abort_dma(devpriv->plx9080_mmio, channel);
+
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+}
+
+static int gsc_hpdi_cancel(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct hpdi_private *devpriv = dev->private;
+
+ writel(0, devpriv->mmio + BOARD_CONTROL_REG);
+ writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG);
+
+ gsc_hpdi_abort_dma(dev, 0);
+
+ return 0;
+}
+
+static int gsc_hpdi_cmd(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct hpdi_private *devpriv = dev->private;
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ unsigned long flags;
+ uint32_t bits;
+
+ if (s->io_bits)
+ return -EINVAL;
+
+ writel(RX_FIFO_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG);
+
+ gsc_hpdi_abort_dma(dev, 0);
+
+ devpriv->dma_desc_index = 0;
+
+ /*
+ * These register are supposedly unused during chained dma,
+ * but I have found that left over values from last operation
+ * occasionally cause problems with transfer of first dma
+ * block. Initializing them to zero seems to fix the problem.
+ */
+ writel(0, devpriv->plx9080_mmio + PLX_DMA0_TRANSFER_SIZE_REG);
+ writel(0, devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG);
+ writel(0, devpriv->plx9080_mmio + PLX_DMA0_LOCAL_ADDRESS_REG);
+
+ /* give location of first dma descriptor */
+ bits = devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT |
+ PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI;
+ writel(bits, devpriv->plx9080_mmio + PLX_DMA0_DESCRIPTOR_REG);
+
+ /* enable dma transfer */
+ spin_lock_irqsave(&dev->spinlock, flags);
+ writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT,
+ devpriv->plx9080_mmio + PLX_DMA0_CS_REG);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+
+ if (cmd->stop_src == TRIG_COUNT)
+ devpriv->dio_count = cmd->stop_arg;
+ else
+ devpriv->dio_count = 1;
+
+ /* clear over/under run status flags */
+ writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT,
+ devpriv->mmio + BOARD_STATUS_REG);
+
+ /* enable interrupts */
+ writel(RX_FULL_INTR, devpriv->mmio + INTERRUPT_CONTROL_REG);
+
+ writel(RX_ENABLE_BIT, devpriv->mmio + BOARD_CONTROL_REG);
+
+ return 0;
+}
+
+static int gsc_hpdi_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ int i;
+
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+
+ if (chan != i) {
+ dev_dbg(dev->class_dev,
+ "chanlist must be ch 0 to 31 in order\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int gsc_hpdi_cmd_test(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ int err = 0;
+
+ if (s->io_bits)
+ return -EINVAL;
+
+ /* Step 1 : check if triggers are trivially valid */
+
+ err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+ err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+ err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+ err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+ err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
+
+ if (err)
+ return 1;
+
+ /* Step 2a : make sure trigger sources are unique */
+
+ err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+ /* Step 2b : and mutually compatible */
+
+ if (err)
+ return 2;
+
+ /* Step 3: check if arguments are trivially valid */
+
+ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+
+ if (!cmd->chanlist_len || !cmd->chanlist) {
+ cmd->chanlist_len = 32;
+ err |= -EINVAL;
+ }
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+
+ if (cmd->stop_src == TRIG_COUNT)
+ err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
+ else /* TRIG_NONE */
+ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
+
+ if (err)
+ return 3;
+
+ /* step 4: fix up any arguments */
+
+ if (err)
+ return 4;
+
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= gsc_hpdi_check_chanlist(dev, s, cmd);
+
+ if (err)
+ return 5;
+
+ return 0;
+
+}
+
+/* setup dma descriptors so a link completes every 'len' bytes */
+static int gsc_hpdi_setup_dma_descriptors(struct comedi_device *dev,
+ unsigned int len)
+{
+ struct hpdi_private *devpriv = dev->private;
+ dma_addr_t phys_addr = devpriv->dma_desc_phys_addr;
+ uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT |
+ PLX_XFER_LOCAL_TO_PCI;
+ unsigned int offset = 0;
+ unsigned int idx = 0;
+ unsigned int i;
+
+ if (len > DMA_BUFFER_SIZE)
+ len = DMA_BUFFER_SIZE;
+ len -= len % sizeof(uint32_t);
+ if (len == 0)
+ return -EINVAL;
+
+ for (i = 0; i < NUM_DMA_DESCRIPTORS && idx < NUM_DMA_BUFFERS; i++) {
+ devpriv->dma_desc[i].pci_start_addr =
+ cpu_to_le32(devpriv->dio_buffer_phys_addr[idx] + offset);
+ devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG);
+ devpriv->dma_desc[i].transfer_size = cpu_to_le32(len);
+ devpriv->dma_desc[i].next = cpu_to_le32((phys_addr +
+ (i + 1) * sizeof(devpriv->dma_desc[0])) | next_bits);
+
+ devpriv->desc_dio_buffer[i] = devpriv->dio_buffer[idx] +
+ (offset / sizeof(uint32_t));
+
+ offset += len;
+ if (len + offset > DMA_BUFFER_SIZE) {
+ offset = 0;
+ idx++;
+ }
+ }
+ devpriv->num_dma_descriptors = i;
+ /* fix last descriptor to point back to first */
+ devpriv->dma_desc[i - 1].next = cpu_to_le32(phys_addr | next_bits);
+
+ devpriv->block_size = len;
+
+ return len;
+}
+
+static int gsc_hpdi_dio_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
int ret;
switch (data[0]) {
case INSN_CONFIG_BLOCK_SIZE:
- return dio_config_block_size(dev, data);
+ ret = gsc_hpdi_setup_dma_descriptors(dev, data[1]);
+ if (ret)
+ return ret;
+
+ data[1] = ret;
+ break;
default:
ret = comedi_dio_insn_config(dev, s, insn, data, 0xffffffff);
if (ret)
@@ -246,57 +511,53 @@ static int dio_config_insn(struct comedi_device *dev,
return insn->n;
}
-static void disable_plx_interrupts(struct comedi_device *dev)
+static int gsc_hpdi_init(struct comedi_device *dev)
{
struct hpdi_private *devpriv = dev->private;
+ uint32_t plx_intcsr_bits;
+
+ /* wait 10usec after reset before accessing fifos */
+ writel(BOARD_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG);
+ udelay(10);
+
+ writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32),
+ devpriv->mmio + RX_PROG_ALMOST_REG);
+ writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32),
+ devpriv->mmio + TX_PROG_ALMOST_REG);
- writel(0, devpriv->plx9080_iobase + PLX_INTRCS_REG);
+ devpriv->tx_fifo_size = readl(devpriv->mmio + TX_FIFO_SIZE_REG) &
+ FIFO_SIZE_MASK;
+ devpriv->rx_fifo_size = readl(devpriv->mmio + RX_FIFO_SIZE_REG) &
+ FIFO_SIZE_MASK;
+
+ writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG);
+
+ /* enable interrupts */
+ plx_intcsr_bits =
+ ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE |
+ ICS_DMA0_E;
+ writel(plx_intcsr_bits, devpriv->plx9080_mmio + PLX_INTRCS_REG);
+
+ return 0;
}
-/* initialize plx9080 chip */
-static void init_plx9080(struct comedi_device *dev)
+static void gsc_hpdi_init_plx9080(struct comedi_device *dev)
{
struct hpdi_private *devpriv = dev->private;
uint32_t bits;
- void __iomem *plx_iobase = devpriv->plx9080_iobase;
-
- /* plx9080 dump */
- DEBUG_PRINT(" plx interrupt status 0x%x\n",
- readl(plx_iobase + PLX_INTRCS_REG));
- DEBUG_PRINT(" plx id bits 0x%x\n", readl(plx_iobase + PLX_ID_REG));
- DEBUG_PRINT(" plx control reg 0x%x\n",
- readl(devpriv->plx9080_iobase + PLX_CONTROL_REG));
-
- DEBUG_PRINT(" plx revision 0x%x\n",
- readl(plx_iobase + PLX_REVISION_REG));
- DEBUG_PRINT(" plx dma channel 0 mode 0x%x\n",
- readl(plx_iobase + PLX_DMA0_MODE_REG));
- DEBUG_PRINT(" plx dma channel 1 mode 0x%x\n",
- readl(plx_iobase + PLX_DMA1_MODE_REG));
- DEBUG_PRINT(" plx dma channel 0 pci address 0x%x\n",
- readl(plx_iobase + PLX_DMA0_PCI_ADDRESS_REG));
- DEBUG_PRINT(" plx dma channel 0 local address 0x%x\n",
- readl(plx_iobase + PLX_DMA0_LOCAL_ADDRESS_REG));
- DEBUG_PRINT(" plx dma channel 0 transfer size 0x%x\n",
- readl(plx_iobase + PLX_DMA0_TRANSFER_SIZE_REG));
- DEBUG_PRINT(" plx dma channel 0 descriptor 0x%x\n",
- readl(plx_iobase + PLX_DMA0_DESCRIPTOR_REG));
- DEBUG_PRINT(" plx dma channel 0 command status 0x%x\n",
- readb(plx_iobase + PLX_DMA0_CS_REG));
- DEBUG_PRINT(" plx dma channel 0 threshold 0x%x\n",
- readl(plx_iobase + PLX_DMA0_THRESHOLD_REG));
- DEBUG_PRINT(" plx bigend 0x%x\n", readl(plx_iobase + PLX_BIGEND_REG));
+ void __iomem *plx_iobase = devpriv->plx9080_mmio;
+
#ifdef __BIG_ENDIAN
bits = BIGEND_DMA0 | BIGEND_DMA1;
#else
bits = 0;
#endif
- writel(bits, devpriv->plx9080_iobase + PLX_BIGEND_REG);
+ writel(bits, devpriv->plx9080_mmio + PLX_BIGEND_REG);
- disable_plx_interrupts(dev);
+ writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG);
- abort_dma(dev, 0);
- abort_dma(dev, 1);
+ gsc_hpdi_abort_dma(dev, 0);
+ gsc_hpdi_abort_dma(dev, 1);
/* configure dma0 mode */
bits = 0;
@@ -320,131 +581,7 @@ static void init_plx9080(struct comedi_device *dev)
writel(bits, plx_iobase + PLX_DMA0_MODE_REG);
}
-/* Allocate and initialize the subdevice structures.
- */
-static int setup_subdevices(struct comedi_device *dev)
-{
- struct comedi_subdevice *s;
- int ret;
-
- ret = comedi_alloc_subdevices(dev, 1);
- if (ret)
- return ret;
-
- s = &dev->subdevices[0];
- /* analog input subdevice */
- dev->read_subdev = s;
-/* dev->write_subdev = s; */
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags =
- SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL | SDF_CMD_READ;
- s->n_chan = 32;
- s->len_chanlist = 32;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_config = dio_config_insn;
- s->do_cmd = hpdi_cmd;
- s->do_cmdtest = hpdi_cmd_test;
- s->cancel = hpdi_cancel;
-
- return 0;
-}
-
-static int init_hpdi(struct comedi_device *dev)
-{
- struct hpdi_private *devpriv = dev->private;
- uint32_t plx_intcsr_bits;
-
- writel(BOARD_RESET_BIT, devpriv->hpdi_iobase + BOARD_CONTROL_REG);
- udelay(10);
-
- writel(almost_empty_bits(32) | almost_full_bits(32),
- devpriv->hpdi_iobase + RX_PROG_ALMOST_REG);
- writel(almost_empty_bits(32) | almost_full_bits(32),
- devpriv->hpdi_iobase + TX_PROG_ALMOST_REG);
-
- devpriv->tx_fifo_size = fifo_size(readl(devpriv->hpdi_iobase +
- TX_FIFO_SIZE_REG));
- devpriv->rx_fifo_size = fifo_size(readl(devpriv->hpdi_iobase +
- RX_FIFO_SIZE_REG));
-
- writel(0, devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG);
-
- /* enable interrupts */
- plx_intcsr_bits =
- ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE |
- ICS_DMA0_E;
- writel(plx_intcsr_bits, devpriv->plx9080_iobase + PLX_INTRCS_REG);
-
- return 0;
-}
-
-/* setup dma descriptors so a link completes every 'transfer_size' bytes */
-static int setup_dma_descriptors(struct comedi_device *dev,
- unsigned int transfer_size)
-{
- struct hpdi_private *devpriv = dev->private;
- unsigned int buffer_index, buffer_offset;
- uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT |
- PLX_XFER_LOCAL_TO_PCI;
- unsigned int i;
-
- if (transfer_size > DMA_BUFFER_SIZE)
- transfer_size = DMA_BUFFER_SIZE;
- transfer_size -= transfer_size % sizeof(uint32_t);
- if (transfer_size == 0)
- return -1;
-
- DEBUG_PRINT(" transfer_size %i\n", transfer_size);
- DEBUG_PRINT(" descriptors at 0x%lx\n",
- (unsigned long)devpriv->dma_desc_phys_addr);
-
- buffer_offset = 0;
- buffer_index = 0;
- for (i = 0; i < NUM_DMA_DESCRIPTORS &&
- buffer_index < NUM_DMA_BUFFERS; i++) {
- devpriv->dma_desc[i].pci_start_addr =
- cpu_to_le32(devpriv->dio_buffer_phys_addr[buffer_index] +
- buffer_offset);
- devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG);
- devpriv->dma_desc[i].transfer_size =
- cpu_to_le32(transfer_size);
- devpriv->dma_desc[i].next =
- cpu_to_le32((devpriv->dma_desc_phys_addr + (i +
- 1) *
- sizeof(devpriv->dma_desc[0])) | next_bits);
-
- devpriv->desc_dio_buffer[i] =
- devpriv->dio_buffer[buffer_index] +
- (buffer_offset / sizeof(uint32_t));
-
- buffer_offset += transfer_size;
- if (transfer_size + buffer_offset > DMA_BUFFER_SIZE) {
- buffer_offset = 0;
- buffer_index++;
- }
-
- DEBUG_PRINT(" desc %i\n", i);
- DEBUG_PRINT(" start addr virt 0x%p, phys 0x%lx\n",
- devpriv->desc_dio_buffer[i],
- (unsigned long)devpriv->dma_desc[i].
- pci_start_addr);
- DEBUG_PRINT(" next 0x%lx\n",
- (unsigned long)devpriv->dma_desc[i].next);
- }
- devpriv->num_dma_descriptors = i;
- /* fix last descriptor to point back to first */
- devpriv->dma_desc[i - 1].next =
- cpu_to_le32(devpriv->dma_desc_phys_addr | next_bits);
- DEBUG_PRINT(" desc %i next fixup 0x%lx\n", i - 1,
- (unsigned long)devpriv->dma_desc[i - 1].next);
-
- devpriv->block_size = transfer_size;
-
- return transfer_size;
-}
-
-static const struct hpdi_board *hpdi_find_board(struct pci_dev *pcidev)
+static const struct hpdi_board *gsc_hpdi_find_board(struct pci_dev *pcidev)
{
unsigned int i;
@@ -455,16 +592,17 @@ static const struct hpdi_board *hpdi_find_board(struct pci_dev *pcidev)
return NULL;
}
-static int hpdi_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+static int gsc_hpdi_auto_attach(struct comedi_device *dev,
+ unsigned long context_unused)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
const struct hpdi_board *thisboard;
struct hpdi_private *devpriv;
+ struct comedi_subdevice *s;
int i;
int retval;
- thisboard = hpdi_find_board(pcidev);
+ thisboard = gsc_hpdi_find_board(pcidev);
if (!thisboard) {
dev_err(dev->class_dev, "gsc_hpdi: pci %s not supported\n",
pci_name(pcidev));
@@ -482,20 +620,17 @@ static int hpdi_auto_attach(struct comedi_device *dev,
return retval;
pci_set_master(pcidev);
- devpriv->plx9080_iobase = pci_ioremap_bar(pcidev, 0);
- devpriv->hpdi_iobase = pci_ioremap_bar(pcidev, 2);
- if (!devpriv->plx9080_iobase || !devpriv->hpdi_iobase) {
+ devpriv->plx9080_mmio = pci_ioremap_bar(pcidev, 0);
+ devpriv->mmio = pci_ioremap_bar(pcidev, 2);
+ if (!devpriv->plx9080_mmio || !devpriv->mmio) {
dev_warn(dev->class_dev, "failed to remap io memory\n");
return -ENOMEM;
}
- DEBUG_PRINT(" plx9080 remapped to 0x%p\n", devpriv->plx9080_iobase);
- DEBUG_PRINT(" hpdi remapped to 0x%p\n", devpriv->hpdi_iobase);
-
- init_plx9080(dev);
+ gsc_hpdi_init_plx9080(dev);
/* get irq */
- if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED,
+ if (request_irq(pcidev->irq, gsc_hpdi_interrupt, IRQF_SHARED,
dev->board_name, dev)) {
dev_warn(dev->class_dev,
"unable to allocate irq %u\n", pcidev->irq);
@@ -510,9 +645,6 @@ static int hpdi_auto_attach(struct comedi_device *dev,
devpriv->dio_buffer[i] =
pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE,
&devpriv->dio_buffer_phys_addr[i]);
- DEBUG_PRINT("dio_buffer at virt 0x%p, phys 0x%lx\n",
- devpriv->dio_buffer[i],
- (unsigned long)devpriv->dio_buffer_phys_addr[i]);
}
/* allocate dma descriptors */
devpriv->dma_desc = pci_alloc_consistent(pcidev,
@@ -525,18 +657,33 @@ static int hpdi_auto_attach(struct comedi_device *dev,
return -EIO;
}
- retval = setup_dma_descriptors(dev, 0x1000);
+ retval = gsc_hpdi_setup_dma_descriptors(dev, 0x1000);
if (retval < 0)
return retval;
- retval = setup_subdevices(dev);
- if (retval < 0)
+ retval = comedi_alloc_subdevices(dev, 1);
+ if (retval)
return retval;
- return init_hpdi(dev);
+ /* Digital I/O subdevice */
+ s = &dev->subdevices[0];
+ dev->read_subdev = s;
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL |
+ SDF_CMD_READ;
+ s->n_chan = 32;
+ s->len_chanlist = 32;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_config = gsc_hpdi_dio_insn_config;
+ s->do_cmd = gsc_hpdi_cmd;
+ s->do_cmdtest = gsc_hpdi_cmd_test;
+ s->cancel = gsc_hpdi_cancel;
+
+ return gsc_hpdi_init(dev);
}
-static void hpdi_detach(struct comedi_device *dev)
+static void gsc_hpdi_detach(struct comedi_device *dev)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct hpdi_private *devpriv = dev->private;
@@ -545,12 +692,12 @@ static void hpdi_detach(struct comedi_device *dev)
if (dev->irq)
free_irq(dev->irq, dev);
if (devpriv) {
- if (devpriv->plx9080_iobase) {
- disable_plx_interrupts(dev);
- iounmap(devpriv->plx9080_iobase);
+ if (devpriv->plx9080_mmio) {
+ writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG);
+ iounmap(devpriv->plx9080_mmio);
}
- if (devpriv->hpdi_iobase)
- iounmap(devpriv->hpdi_iobase);
+ if (devpriv->mmio)
+ iounmap(devpriv->mmio);
/* free pci dma buffers */
for (i = 0; i < NUM_DMA_BUFFERS; i++) {
if (devpriv->dio_buffer[i])
@@ -571,341 +718,11 @@ static void hpdi_detach(struct comedi_device *dev)
comedi_pci_disable(dev);
}
-static int dio_config_block_size(struct comedi_device *dev, unsigned int *data)
-{
- unsigned int requested_block_size;
- int retval;
-
- requested_block_size = data[1];
-
- retval = setup_dma_descriptors(dev, requested_block_size);
- if (retval < 0)
- return retval;
-
- data[1] = retval;
-
- return 2;
-}
-
-static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
-{
- int err = 0;
- int i;
-
- /* Step 1 : check if triggers are trivially valid */
-
- err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
- err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
- err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
- err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
- err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
-
- if (err)
- return 1;
-
- /* Step 2a : make sure trigger sources are unique */
-
- err |= cfc_check_trigger_is_unique(cmd->stop_src);
-
- /* Step 2b : and mutually compatible */
-
- if (err)
- return 2;
-
- /* Step 3: check if arguments are trivially valid */
-
- if (!cmd->chanlist_len) {
- cmd->chanlist_len = 32;
- err |= -EINVAL;
- }
- err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
-
- switch (cmd->stop_src) {
- case TRIG_COUNT:
- err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
- break;
- case TRIG_NONE:
- err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
- break;
- default:
- break;
- }
-
- if (err)
- return 3;
-
- /* step 4: fix up any arguments */
-
- if (err)
- return 4;
-
- if (!cmd->chanlist)
- return 0;
-
- for (i = 1; i < cmd->chanlist_len; i++) {
- if (CR_CHAN(cmd->chanlist[i]) != i) {
- /* XXX could support 8 or 16 channels */
- comedi_error(dev,
- "chanlist must be ch 0 to 31 in order");
- err++;
- break;
- }
- }
-
- if (err)
- return 5;
-
- return 0;
-}
-
-static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
-{
- if (s->io_bits)
- return -EINVAL;
- else
- return di_cmd_test(dev, s, cmd);
-}
-
-static inline void hpdi_writel(struct comedi_device *dev, uint32_t bits,
- unsigned int offset)
-{
- struct hpdi_private *devpriv = dev->private;
-
- writel(bits | devpriv->bits[offset / sizeof(uint32_t)],
- devpriv->hpdi_iobase + offset);
-}
-
-static int di_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- struct hpdi_private *devpriv = dev->private;
- uint32_t bits;
- unsigned long flags;
- struct comedi_async *async = s->async;
- struct comedi_cmd *cmd = &async->cmd;
-
- hpdi_writel(dev, RX_FIFO_RESET_BIT, BOARD_CONTROL_REG);
-
- DEBUG_PRINT("hpdi: in di_cmd\n");
-
- abort_dma(dev, 0);
-
- devpriv->dma_desc_index = 0;
-
- /* These register are supposedly unused during chained dma,
- * but I have found that left over values from last operation
- * occasionally cause problems with transfer of first dma
- * block. Initializing them to zero seems to fix the problem. */
- writel(0, devpriv->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG);
- writel(0, devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG);
- writel(0, devpriv->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG);
- /* give location of first dma descriptor */
- bits =
- devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT |
- PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI;
- writel(bits, devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG);
-
- /* spinlock for plx dma control/status reg */
- spin_lock_irqsave(&dev->spinlock, flags);
- /* enable dma transfer */
- writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT,
- devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- if (cmd->stop_src == TRIG_COUNT)
- devpriv->dio_count = cmd->stop_arg;
- else
- devpriv->dio_count = 1;
-
- /* clear over/under run status flags */
- writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT,
- devpriv->hpdi_iobase + BOARD_STATUS_REG);
- /* enable interrupts */
- writel(intr_bit(RX_FULL_INTR),
- devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG);
-
- DEBUG_PRINT("hpdi: starting rx\n");
- hpdi_writel(dev, RX_ENABLE_BIT, BOARD_CONTROL_REG);
-
- return 0;
-}
-
-static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- if (s->io_bits)
- return -EINVAL;
- else
- return di_cmd(dev, s);
-}
-
-static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel)
-{
- struct hpdi_private *devpriv = dev->private;
- struct comedi_async *async = dev->read_subdev->async;
- uint32_t next_transfer_addr;
- int j;
- int num_samples = 0;
- void __iomem *pci_addr_reg;
-
- if (channel)
- pci_addr_reg =
- devpriv->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG;
- else
- pci_addr_reg =
- devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG;
-
- /* loop until we have read all the full buffers */
- j = 0;
- for (next_transfer_addr = readl(pci_addr_reg);
- (next_transfer_addr <
- le32_to_cpu(devpriv->dma_desc[devpriv->dma_desc_index].
- pci_start_addr)
- || next_transfer_addr >=
- le32_to_cpu(devpriv->dma_desc[devpriv->dma_desc_index].
- pci_start_addr) + devpriv->block_size)
- && j < devpriv->num_dma_descriptors; j++) {
- /* transfer data from dma buffer to comedi buffer */
- num_samples = devpriv->block_size / sizeof(uint32_t);
- if (async->cmd.stop_src == TRIG_COUNT) {
- if (num_samples > devpriv->dio_count)
- num_samples = devpriv->dio_count;
- devpriv->dio_count -= num_samples;
- }
- cfc_write_array_to_buffer(dev->read_subdev,
- devpriv->desc_dio_buffer[devpriv->
- dma_desc_index],
- num_samples * sizeof(uint32_t));
- devpriv->dma_desc_index++;
- devpriv->dma_desc_index %= devpriv->num_dma_descriptors;
-
- DEBUG_PRINT("next desc addr 0x%lx\n", (unsigned long)
- devpriv->dma_desc[devpriv->dma_desc_index].
- next);
- DEBUG_PRINT("pci addr reg 0x%x\n", next_transfer_addr);
- }
- /* XXX check for buffer overrun somehow */
-}
-
-static irqreturn_t handle_interrupt(int irq, void *d)
-{
- struct comedi_device *dev = d;
- struct hpdi_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
- struct comedi_async *async = s->async;
- uint32_t hpdi_intr_status, hpdi_board_status;
- uint32_t plx_status;
- uint32_t plx_bits;
- uint8_t dma0_status, dma1_status;
- unsigned long flags;
-
- if (!dev->attached)
- return IRQ_NONE;
-
- plx_status = readl(devpriv->plx9080_iobase + PLX_INTRCS_REG);
- if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0)
- return IRQ_NONE;
-
- hpdi_intr_status = readl(devpriv->hpdi_iobase + INTERRUPT_STATUS_REG);
- hpdi_board_status = readl(devpriv->hpdi_iobase + BOARD_STATUS_REG);
-
- async->events = 0;
-
- if (hpdi_intr_status) {
- DEBUG_PRINT("hpdi: intr status 0x%x, ", hpdi_intr_status);
- writel(hpdi_intr_status,
- devpriv->hpdi_iobase + INTERRUPT_STATUS_REG);
- }
- /* spin lock makes sure no one else changes plx dma control reg */
- spin_lock_irqsave(&dev->spinlock, flags);
- dma0_status = readb(devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
- if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */
- writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT,
- devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
-
- DEBUG_PRINT("dma0 status 0x%x\n", dma0_status);
- if (dma0_status & PLX_DMA_EN_BIT)
- drain_dma_buffers(dev, 0);
- DEBUG_PRINT(" cleared dma ch0 interrupt\n");
- }
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- /* spin lock makes sure no one else changes plx dma control reg */
- spin_lock_irqsave(&dev->spinlock, flags);
- dma1_status = readb(devpriv->plx9080_iobase + PLX_DMA1_CS_REG);
- if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */
- writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT,
- devpriv->plx9080_iobase + PLX_DMA1_CS_REG);
- DEBUG_PRINT("dma1 status 0x%x\n", dma1_status);
-
- DEBUG_PRINT(" cleared dma ch1 interrupt\n");
- }
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- /* clear possible plx9080 interrupt sources */
- if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */
- plx_bits = readl(devpriv->plx9080_iobase + PLX_DBR_OUT_REG);
- writel(plx_bits, devpriv->plx9080_iobase + PLX_DBR_OUT_REG);
- DEBUG_PRINT(" cleared local doorbell bits 0x%x\n", plx_bits);
- }
-
- if (hpdi_board_status & RX_OVERRUN_BIT) {
- comedi_error(dev, "rx fifo overrun");
- async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- DEBUG_PRINT("dma0_status 0x%x\n",
- (int)readb(devpriv->plx9080_iobase +
- PLX_DMA0_CS_REG));
- }
-
- if (hpdi_board_status & RX_UNDERRUN_BIT) {
- comedi_error(dev, "rx fifo underrun");
- async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- }
-
- if (devpriv->dio_count == 0)
- async->events |= COMEDI_CB_EOA;
-
- DEBUG_PRINT("board status 0x%x, ", hpdi_board_status);
- DEBUG_PRINT("plx status 0x%x\n", plx_status);
- if (async->events)
- DEBUG_PRINT(" events 0x%x\n", async->events);
-
- cfc_handle_events(dev, s);
-
- return IRQ_HANDLED;
-}
-
-static void abort_dma(struct comedi_device *dev, unsigned int channel)
-{
- struct hpdi_private *devpriv = dev->private;
- unsigned long flags;
-
- /* spinlock for plx dma control/status reg */
- spin_lock_irqsave(&dev->spinlock, flags);
-
- plx9080_abort_dma(devpriv->plx9080_iobase, channel);
-
- spin_unlock_irqrestore(&dev->spinlock, flags);
-}
-
-static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- struct hpdi_private *devpriv = dev->private;
-
- hpdi_writel(dev, 0, BOARD_CONTROL_REG);
-
- writel(0, devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG);
-
- abort_dma(dev, 0);
-
- return 0;
-}
-
static struct comedi_driver gsc_hpdi_driver = {
.driver_name = "gsc_hpdi",
.module = THIS_MODULE,
- .auto_attach = hpdi_auto_attach,
- .detach = hpdi_detach,
+ .auto_attach = gsc_hpdi_auto_attach,
+ .detach = gsc_hpdi_detach,
};
static int gsc_hpdi_pci_probe(struct pci_dev *dev,
@@ -914,7 +731,7 @@ static int gsc_hpdi_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &gsc_hpdi_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(gsc_hpdi_pci_table) = {
+static const struct pci_device_id gsc_hpdi_pci_table[] = {
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX,
0x2400, 0, 0, 0},
{ 0 }
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c
index 1e16641ec52..0b8b2162b76 100644
--- a/drivers/staging/comedi/drivers/icp_multi.c
+++ b/drivers/staging/comedi/drivers/icp_multi.c
@@ -91,12 +91,13 @@ Configuration options: not applicable, uses PCI auto config
#define Status_IRQ 0x00ff /* All interrupts */
/* Define analogue range */
-static const struct comedi_lrange range_analog = { 4, {
- UNI_RANGE(5),
- UNI_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(10)
- }
+static const struct comedi_lrange range_analog = {
+ 4, {
+ UNI_RANGE(5),
+ UNI_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(10)
+ }
};
static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 };
@@ -170,12 +171,27 @@ static void setup_channel_list(struct comedi_device *dev,
}
}
+static int icp_multi_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct icp_multi_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readw(devpriv->io_addr + ICP_MULTI_ADC_CSR);
+ if ((status & ADC_BSY) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int icp_multi_insn_read_ai(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct icp_multi_private *devpriv = dev->private;
- int n, timeout;
+ int ret = 0;
+ int n;
/* Disable A/D conversion ready interrupt */
devpriv->IntEnable &= ~ADC_READY;
@@ -198,33 +214,10 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev,
udelay(1);
/* Wait for conversion to complete, or get fed up waiting */
- timeout = 100;
- while (timeout--) {
- if (!(readw(devpriv->io_addr +
- ICP_MULTI_ADC_CSR) & ADC_BSY))
- goto conv_finish;
+ ret = comedi_timeout(dev, s, insn, icp_multi_ai_eoc, 0);
+ if (ret)
+ break;
- udelay(1);
- }
-
- /* If we reach here, a timeout has occurred */
- comedi_error(dev, "A/D insn timeout");
-
- /* Disable interrupt */
- devpriv->IntEnable &= ~ADC_READY;
- writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN);
-
- /* Clear interrupt status */
- devpriv->IntStatus |= ADC_READY;
- writew(devpriv->IntStatus,
- devpriv->io_addr + ICP_MULTI_INT_STAT);
-
- /* Clear data received */
- data[n] = 0;
-
- return -ETIME;
-
-conv_finish:
data[n] =
(readw(devpriv->io_addr + ICP_MULTI_AI) >> 4) & 0x0fff;
}
@@ -237,7 +230,21 @@ conv_finish:
devpriv->IntStatus |= ADC_READY;
writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT);
- return n;
+ 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)
+{
+ struct icp_multi_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readw(devpriv->io_addr + ICP_MULTI_DAC_CSR);
+ if ((status & DAC_BSY) == 0)
+ return 0;
+ return -EBUSY;
}
static int icp_multi_insn_write_ao(struct comedi_device *dev,
@@ -245,7 +252,8 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev,
struct comedi_insn *insn, unsigned int *data)
{
struct icp_multi_private *devpriv = dev->private;
- int n, chan, range, timeout;
+ int n, chan, range;
+ int ret;
/* Disable D/A conversion ready interrupt */
devpriv->IntEnable &= ~DAC_READY;
@@ -273,33 +281,24 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev,
for (n = 0; n < insn->n; n++) {
/* Wait for analogue output data register to be
* ready for new data, or get fed up waiting */
- timeout = 100;
- while (timeout--) {
- if (!(readw(devpriv->io_addr +
- ICP_MULTI_DAC_CSR) & DAC_BSY))
- goto dac_ready;
-
- udelay(1);
+ ret = comedi_timeout(dev, s, insn, icp_multi_ao_eoc, 0);
+ if (ret) {
+ /* Disable interrupt */
+ devpriv->IntEnable &= ~DAC_READY;
+ writew(devpriv->IntEnable,
+ devpriv->io_addr + ICP_MULTI_INT_EN);
+
+ /* Clear interrupt status */
+ devpriv->IntStatus |= DAC_READY;
+ writew(devpriv->IntStatus,
+ devpriv->io_addr + ICP_MULTI_INT_STAT);
+
+ /* Clear data received */
+ devpriv->ao_data[chan] = 0;
+
+ return ret;
}
- /* If we reach here, a timeout has occurred */
- comedi_error(dev, "D/A insn timeout");
-
- /* Disable interrupt */
- devpriv->IntEnable &= ~DAC_READY;
- writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN);
-
- /* Clear interrupt status */
- devpriv->IntStatus |= DAC_READY;
- writew(devpriv->IntStatus,
- devpriv->io_addr + ICP_MULTI_INT_STAT);
-
- /* Clear data received */
- devpriv->ao_data[chan] = 0;
-
- return -ETIME;
-
-dac_ready:
/* Write data to analogue output data register */
writew(data[n], devpriv->io_addr + ICP_MULTI_AO);
@@ -564,9 +563,6 @@ static int icp_multi_auto_attach(struct comedi_device *dev,
devpriv->valid = 1;
- dev_info(dev->class_dev, "%s attached, irq %sabled\n",
- dev->board_name, dev->irq ? "en" : "dis");
-
return 0;
}
@@ -597,7 +593,7 @@ static int icp_multi_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &icp_multi_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(icp_multi_pci_table) = {
+static const struct pci_device_id icp_multi_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ICP, PCI_DEVICE_ID_ICP_MULTI) },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index 8577778441f..2516ce83483 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -190,20 +190,18 @@ static int ii20k_ao_insn_write(struct comedi_device *dev,
return insn->n;
}
-static int ii20k_ai_wait_eoc(struct comedi_device *dev,
- struct comedi_subdevice *s,
- int timeout)
+static int ii20k_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
void __iomem *iobase = ii20k_module_iobase(dev, s);
unsigned char status;
- do {
- status = readb(iobase + II20K_AI_STATUS_REG);
- if ((status & II20K_AI_STATUS_INT) == 0)
- return 0;
- } while (timeout--);
-
- return -ETIME;
+ status = readb(iobase + II20K_AI_STATUS_REG);
+ if ((status & II20K_AI_STATUS_INT) == 0)
+ return 0;
+ return -EBUSY;
}
static void ii20k_ai_setup(struct comedi_device *dev,
@@ -263,7 +261,7 @@ static int ii20k_ai_insn_read(struct comedi_device *dev,
/* generate a software start convert signal */
readb(iobase + II20K_AI_PACER_RESET_REG);
- ret = ii20k_ai_wait_eoc(dev, s, 100);
+ ret = comedi_timeout(dev, s, insn, ii20k_ai_eoc, 0);
if (ret)
return ret;
@@ -463,6 +461,7 @@ static int ii20k_attach(struct comedi_device *dev,
id = readb(devpriv->ioaddr + II20K_ID_REG);
switch (id & II20K_ID_MASK) {
case II20K_ID_PCI20001C_1A:
+ has_dio = false;
break;
case II20K_ID_PCI20001C_2A:
has_dio = true;
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index b52d58e5de2..a8db9d86aad 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -51,23 +51,55 @@
#include "jr3_pci.h"
#define PCI_VENDOR_ID_JR3 0x1762
-#define PCI_DEVICE_ID_JR3_1_CHANNEL 0x3111
-#define PCI_DEVICE_ID_JR3_1_CHANNEL_NEW 0x1111
-#define PCI_DEVICE_ID_JR3_2_CHANNEL 0x3112
-#define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113
-#define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114
-struct jr3_pci_dev_private {
- struct jr3_t __iomem *iobase;
- int n_channels;
- struct timer_list timer;
+enum jr3_pci_boardid {
+ BOARD_JR3_1,
+ BOARD_JR3_2,
+ BOARD_JR3_3,
+ BOARD_JR3_4,
};
-struct poll_delay_t {
+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 jr3_t __iomem *iobase;
+ struct timer_list timer;
+};
+
struct jr3_pci_subdev_private {
struct jr3_channel __iomem *channel;
unsigned long next_time_min;
@@ -79,7 +111,6 @@ struct jr3_pci_subdev_private {
state_jr3_init_use_offset_complete,
state_jr3_done
} state;
- int channel_no;
int serial_no;
int model_no;
struct {
@@ -92,9 +123,9 @@ struct jr3_pci_subdev_private {
int retries;
};
-static struct poll_delay_t poll_delay_min_max(int min, int max)
+static struct jr3_pci_poll_delay poll_delay_min_max(int min, int max)
{
- struct poll_delay_t result;
+ struct jr3_pci_poll_delay result;
result.min = min;
result.max = max;
@@ -106,15 +137,8 @@ static int is_complete(struct jr3_channel __iomem *channel)
return get_s16(&channel->command_word0) == 0;
}
-struct transform_t {
- struct {
- u16 link_type;
- s16 link_amount;
- } link[8];
-};
-
static void set_transforms(struct jr3_channel __iomem *channel,
- struct transform_t transf, short num)
+ struct jr3_pci_transform transf, short num)
{
int i;
@@ -194,110 +218,99 @@ static struct six_axis_t get_max_full_scales(struct jr3_channel __iomem
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 filter = chan / 8;
+
+ switch (axis) {
+ case 0:
+ val = get_s16(&spriv->channel->filter[filter].fx);
+ break;
+ case 1:
+ val = get_s16(&spriv->channel->filter[filter].fy);
+ break;
+ case 2:
+ val = get_s16(&spriv->channel->filter[filter].fz);
+ break;
+ case 3:
+ val = get_s16(&spriv->channel->filter[filter].mx);
+ break;
+ case 4:
+ val = get_s16(&spriv->channel->filter[filter].my);
+ break;
+ case 5:
+ val = get_s16(&spriv->channel->filter[filter].mz);
+ break;
+ case 6:
+ val = get_s16(&spriv->channel->filter[filter].v1);
+ break;
+ case 7:
+ val = get_s16(&spriv->channel->filter[filter].v2);
+ break;
+ }
+ val += 0x4000;
+ } else if (chan == 56) {
+ val = get_u16(&spriv->channel->model_no);
+ } else if (chan == 57) {
+ val = get_u16(&spriv->channel->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 comedi_insn *insn,
+ unsigned int *data)
{
- int result;
- struct jr3_pci_subdev_private *p;
- int channel;
-
- p = s->private;
- channel = CR_CHAN(insn->chanspec);
- if (p == NULL || channel > 57) {
- result = -EINVAL;
- } else {
- int i;
-
- result = insn->n;
- if (p->state != state_jr3_done ||
- (get_u16(&p->channel->errors) & (watch_dog | watch_dog2 |
- sensor_change))) {
- /* No sensor or sensor changed */
- if (p->state == state_jr3_done) {
- /* Restart polling */
- p->state = state_jr3_poll;
- }
- result = -EAGAIN;
- }
- for (i = 0; i < insn->n; i++) {
- if (channel < 56) {
- int axis, filter;
-
- axis = channel % 8;
- filter = channel / 8;
- if (p->state != state_jr3_done) {
- data[i] = 0;
- } else {
- int F = 0;
- switch (axis) {
- case 0:
- F = get_s16(&p->channel->
- filter[filter].fx);
- break;
- case 1:
- F = get_s16(&p->channel->
- filter[filter].fy);
- break;
- case 2:
- F = get_s16(&p->channel->
- filter[filter].fz);
- break;
- case 3:
- F = get_s16(&p->channel->
- filter[filter].mx);
- break;
- case 4:
- F = get_s16(&p->channel->
- filter[filter].my);
- break;
- case 5:
- F = get_s16(&p->channel->
- filter[filter].mz);
- break;
- case 6:
- F = get_s16(&p->channel->
- filter[filter].v1);
- break;
- case 7:
- F = get_s16(&p->channel->
- filter[filter].v2);
- break;
- }
- data[i] = F + 0x4000;
- }
- } else if (channel == 56) {
- if (p->state != state_jr3_done)
- data[i] = 0;
- else
- data[i] =
- get_u16(&p->channel->model_no);
- } else if (channel == 57) {
- if (p->state != state_jr3_done)
- data[i] = 0;
- else
- data[i] =
- get_u16(&p->channel->serial_no);
- }
+ struct jr3_pci_subdev_private *spriv = s->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ u16 errors;
+ int i;
+
+ if (!spriv)
+ return -EINVAL;
+
+ errors = get_u16(&spriv->channel->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;
}
- return result;
+
+ 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;
- struct jr3_pci_dev_private *devpriv = dev->private;
dev_dbg(dev->class_dev, "jr3_pci_open\n");
- for (i = 0; i < devpriv->n_channels; i++) {
- struct jr3_pci_subdev_private *p;
-
- p = dev->subdevices[i].private;
- if (p) {
- dev_dbg(dev->class_dev, "serial: %p %d (%d)\n", p,
- p->serial_no, p->channel_no);
- }
+ for (i = 0; i < dev->n_subdevices; i++) {
+ s = &dev->subdevices[i];
+ spriv = s->private;
+ if (spriv)
+ dev_dbg(dev->class_dev, "serial: %p %d (%d)\n",
+ spriv, spriv->serial_no, s->index);
}
return 0;
}
@@ -326,271 +339,262 @@ static int read_idm_word(const u8 *data, size_t size, int *pos,
return result;
}
-static int jr3_download_firmware(struct comedi_device *dev,
- const u8 *data, size_t size,
- unsigned long context)
+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
*/
- int result, more, pos, OK;
-
- result = 0;
- more = 1;
- pos = 0;
- OK = 0;
while (more) {
- unsigned int count, addr;
+ unsigned int count = 0;
+ unsigned int addr = 0;
more = more && read_idm_word(data, size, &pos, &count);
- if (more && count == 0xffff) {
- OK = 1;
- break;
- }
+ if (more && count == 0xffff)
+ return 0;
+
more = more && read_idm_word(data, size, &pos, &addr);
while (more && count > 0) {
- unsigned int dummy;
+ unsigned int dummy = 0;
+
more = more && read_idm_word(data, size, &pos, &dummy);
count--;
}
}
- if (!OK) {
- result = -ENODATA;
- } else {
- int i;
- struct jr3_pci_dev_private *p = dev->private;
+ return -ENODATA;
+}
+
+static void jr3_write_firmware(struct comedi_device *dev,
+ int subdev, const u8 *data, size_t size)
+{
+ struct jr3_pci_dev_private *devpriv = dev->private;
+ struct jr3_t __iomem *iobase = devpriv->iobase;
+ 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;
- for (i = 0; i < p->n_channels; i++) {
- struct jr3_pci_subdev_private *sp;
+ 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 = &iobase->channel[subdev].program_lo[addr];
+ hi = &iobase->channel[subdev].program_hi[addr];
- sp = dev->subdevices[i].private;
- more = 1;
- pos = 0;
- while (more) {
- unsigned int count, addr;
more = more &&
- read_idm_word(data, size, &pos, &count);
- if (more && count == 0xffff)
- break;
+ read_idm_word(data, size, &pos, &data1);
more = more &&
- read_idm_word(data, size, &pos, &addr);
- dev_dbg(dev->class_dev,
- "Loading#%d %4.4x bytes at %4.4x\n",
- i, count, addr);
- while (more && count > 0) {
- if (addr & 0x4000) {
- /* 16 bit data, never seen
- * in real life!! */
- unsigned int data1;
-
- more = more &&
- read_idm_word(data,
- size, &pos,
- &data1);
- count--;
- /* jr3[addr + 0x20000 * pnum] =
- data1; */
- } else {
- /* Download 24 bit program */
- unsigned int data1, data2;
-
- more = more &&
- read_idm_word(data,
- size, &pos,
- &data1);
- more = more &&
- read_idm_word(data, size,
- &pos,
- &data2);
- count -= 2;
- if (more) {
- set_u16(&p->
- iobase->channel
- [i].program_low
- [addr], data1);
- udelay(1);
- set_u16(&p->
- iobase->channel
- [i].program_high
- [addr], data2);
- udelay(1);
- }
- }
- addr++;
+ read_idm_word(data, size, &pos, &data2);
+ count -= 2;
+ if (more) {
+ set_u16(lo, data1);
+ udelay(1);
+ set_u16(hi, data2);
+ udelay(1);
}
}
+ addr++;
}
}
- return result;
}
-static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice *s)
+static int jr3_download_firmware(struct comedi_device *dev,
+ const u8 *data, size_t size,
+ unsigned long context)
{
- struct poll_delay_t result = poll_delay_min_max(1000, 2000);
- struct jr3_pci_subdev_private *p = s->private;
- int i;
+ int subdev;
+ int ret;
- if (p) {
- struct jr3_channel __iomem *channel = p->channel;
- int errors = get_u16(&channel->errors);
-
- if (errors != p->errors)
- p->errors = errors;
-
- if (errors & (watch_dog | watch_dog2 | sensor_change))
- /* Sensor communication lost, force poll mode */
- p->state = state_jr3_poll;
-
- switch (p->state) {
- case state_jr3_poll: {
- u16 model_no = get_u16(&channel->model_no);
- u16 serial_no = get_u16(&channel->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.
- */
- result = poll_delay_min_max(1000, 2000);
- } else {
- p->retries = 0;
- p->state =
- state_jr3_init_wait_for_offset;
- result = poll_delay_min_max(1000, 2000);
- }
- }
- break;
- case state_jr3_init_wait_for_offset:
- p->retries++;
- if (p->retries < 10) {
- /* Wait for offeset to stabilize
- * (< 10 s according to manual) */
- result = poll_delay_min_max(1000, 2000);
- } else {
- struct transform_t transf;
+ /* verify IDM file format */
+ ret = jr3_check_firmware(dev, data, size);
+ if (ret)
+ return ret;
- p->model_no = get_u16(&channel->model_no);
- p->serial_no = get_u16(&channel->serial_no);
+ /* write firmware to each subdevice */
+ for (subdev = 0; subdev < dev->n_subdevices; subdev++)
+ jr3_write_firmware(dev, subdev, data, size);
- /* 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;
- }
+ return 0;
+}
- set_transforms(channel, transf, 0);
- use_transform(channel, 0);
- p->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(channel)) {
- result = poll_delay_min_max(20, 100);
- } else {
- /* Set full scale */
- struct six_axis_t min_full_scale;
- struct six_axis_t max_full_scale;
-
- min_full_scale = get_min_full_scales(channel);
- max_full_scale = get_max_full_scales(channel);
- set_full_scales(channel, max_full_scale);
-
- p->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(channel)) {
- result = poll_delay_min_max(20, 100);
- } else {
- struct force_array __iomem *full_scale;
-
- /* Use ranges in kN or we will
- * overflow around 2000N! */
- full_scale = &channel->full_scale;
- p->range[0].range.min =
- -get_s16(&full_scale->fx) * 1000;
- p->range[0].range.max =
- get_s16(&full_scale->fx) * 1000;
- p->range[1].range.min =
- -get_s16(&full_scale->fy) * 1000;
- p->range[1].range.max =
- get_s16(&full_scale->fy) * 1000;
- p->range[2].range.min =
- -get_s16(&full_scale->fz) * 1000;
- p->range[2].range.max =
- get_s16(&full_scale->fz) * 1000;
- p->range[3].range.min =
- -get_s16(&full_scale->mx) * 100;
- p->range[3].range.max =
- get_s16(&full_scale->mx) * 100;
- p->range[4].range.min =
- -get_s16(&full_scale->my) * 100;
- p->range[4].range.max =
- get_s16(&full_scale->my) * 100;
- p->range[5].range.min =
- -get_s16(&full_scale->mz) * 100;
- p->range[5].range.max =
- get_s16(&full_scale->mz) * 100; /* ?? */
- p->range[6].range.min =
- -get_s16(&full_scale->v1) * 100;/* ?? */
- p->range[6].range.max =
- get_s16(&full_scale->v1) * 100; /* ?? */
- p->range[7].range.min =
- -get_s16(&full_scale->v2) * 100;/* ?? */
- p->range[7].range.max =
- get_s16(&full_scale->v2) * 100; /* ?? */
- p->range[8].range.min = 0;
- p->range[8].range.max = 65535;
-
- use_offset(channel, 0);
- p->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(channel)) {
- result = poll_delay_min_max(20, 100);
- } else {
- set_s16(&channel->offsets.fx, 0);
- set_s16(&channel->offsets.fy, 0);
- set_s16(&channel->offsets.fz, 0);
- set_s16(&channel->offsets.mx, 0);
- set_s16(&channel->offsets.my, 0);
- set_s16(&channel->offsets.mz, 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_channel __iomem *channel;
+ u16 model_no;
+ u16 serial_no;
+ int errors;
+ int i;
- set_offset(channel);
+ if (!spriv)
+ return result;
- p->state = state_jr3_done;
+ channel = spriv->channel;
+ errors = get_u16(&channel->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(&channel->model_no);
+ serial_no = get_u16(&channel->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(&channel->model_no);
+ spriv->serial_no = get_u16(&channel->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;
}
- break;
- case state_jr3_done:
- poll_delay_min_max(10000, 20000);
- break;
- default:
- poll_delay_min_max(1000, 2000);
- break;
+
+ set_transforms(channel, transf, 0);
+ use_transform(channel, 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(channel)) {
+ result = poll_delay_min_max(20, 100);
+ } else {
+ /* Set full scale */
+ struct six_axis_t min_full_scale;
+ struct six_axis_t max_full_scale;
+
+ min_full_scale = get_min_full_scales(channel);
+ max_full_scale = get_max_full_scales(channel);
+ set_full_scales(channel, 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(channel)) {
+ result = poll_delay_min_max(20, 100);
+ } else {
+ struct force_array __iomem *fs = &channel->full_scale;
+
+ /* Use ranges in kN or we will overflow around 2000N! */
+ spriv->range[0].range.min = -get_s16(&fs->fx) * 1000;
+ spriv->range[0].range.max = get_s16(&fs->fx) * 1000;
+ spriv->range[1].range.min = -get_s16(&fs->fy) * 1000;
+ spriv->range[1].range.max = get_s16(&fs->fy) * 1000;
+ spriv->range[2].range.min = -get_s16(&fs->fz) * 1000;
+ spriv->range[2].range.max = get_s16(&fs->fz) * 1000;
+ spriv->range[3].range.min = -get_s16(&fs->mx) * 100;
+ spriv->range[3].range.max = get_s16(&fs->mx) * 100;
+ spriv->range[4].range.min = -get_s16(&fs->my) * 100;
+ spriv->range[4].range.max = get_s16(&fs->my) * 100;
+ spriv->range[5].range.min = -get_s16(&fs->mz) * 100;
+ /* the next five are questionable */
+ spriv->range[5].range.max = get_s16(&fs->mz) * 100;
+ spriv->range[6].range.min = -get_s16(&fs->v1) * 100;
+ spriv->range[6].range.max = get_s16(&fs->v1) * 100;
+ spriv->range[7].range.min = -get_s16(&fs->v2) * 100;
+ spriv->range[7].range.max = get_s16(&fs->v2) * 100;
+ spriv->range[8].range.min = 0;
+ spriv->range[8].range.max = 65535;
+
+ use_offset(channel, 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(channel)) {
+ result = poll_delay_min_max(20, 100);
+ } else {
+ set_s16(&channel->offsets.fx, 0);
+ set_s16(&channel->offsets.fy, 0);
+ set_s16(&channel->offsets.fz, 0);
+ set_s16(&channel->offsets.mx, 0);
+ set_s16(&channel->offsets.my, 0);
+ set_s16(&channel->offsets.mz, 0);
+
+ set_offset(channel);
+
+ 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(unsigned long data)
{
- unsigned long flags;
struct comedi_device *dev = (struct comedi_device *)data;
struct jr3_pci_dev_private *devpriv = dev->private;
+ struct jr3_pci_subdev_private *spriv;
+ struct comedi_subdevice *s;
+ unsigned long flags;
unsigned long now;
int delay;
int i;
@@ -598,18 +602,22 @@ static void jr3_pci_poll_dev(unsigned long data)
spin_lock_irqsave(&dev->spinlock, flags);
delay = 1000;
now = jiffies;
- /* Poll all channels that are ready to be polled */
- for (i = 0; i < devpriv->n_channels; i++) {
- struct jr3_pci_subdev_private *subdevpriv =
- dev->subdevices[i].private;
- if (now > subdevpriv->next_time_min) {
- struct poll_delay_t sub_delay;
-
- sub_delay = jr3_pci_poll_subdevice(&dev->subdevices[i]);
- subdevpriv->next_time_min =
- jiffies + msecs_to_jiffies(sub_delay.min);
- subdevpriv->next_time_max =
- jiffies + msecs_to_jiffies(sub_delay.max);
+
+ /* Poll all channels that are ready to be polled */
+ for (i = 0; i < dev->n_subdevices; i++) {
+ s = &dev->subdevices[i];
+ spriv = s->private;
+
+ if (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);
+ spriv->next_time_max = jiffies +
+ msecs_to_jiffies(sub_delay.max);
+
if (sub_delay.max && sub_delay.max < delay)
/*
* Wake up as late as possible ->
@@ -624,13 +632,58 @@ static void jr3_pci_poll_dev(unsigned long data)
add_timer(&devpriv->timer);
}
+static struct jr3_pci_subdev_private *
+jr3_pci_alloc_spriv(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+ struct jr3_pci_dev_private *devpriv = dev->private;
+ struct jr3_pci_subdev_private *spriv;
+ int j;
+ int k;
+
+ spriv = comedi_alloc_spriv(s, sizeof(*spriv));
+ if (!spriv)
+ return NULL;
+
+ spriv->channel = &devpriv->iobase->channel[s->index].data;
+
+ for (j = 0; j < 8; j++) {
+ spriv->range[j].length = 1;
+ spriv->range[j].range.min = -1000000;
+ spriv->range[j].range.max = 1000000;
+
+ for (k = 0; k < 7; k++) {
+ spriv->range_table_list[j + k * 8] =
+ (struct comedi_lrange *)&spriv->range[j];
+ spriv->maxdata_list[j + k * 8] = 0x7fff;
+ }
+ }
+ spriv->range[8].length = 1;
+ spriv->range[8].range.min = 0;
+ spriv->range[8].range.max = 65536;
+
+ spriv->range_table_list[56] = (struct comedi_lrange *)&spriv->range[8];
+ spriv->range_table_list[57] = (struct comedi_lrange *)&spriv->range[8];
+ spriv->maxdata_list[56] = 0xffff;
+ spriv->maxdata_list[57] = 0xffff;
+
+ dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n",
+ spriv->channel, devpriv->iobase,
+ ((char __iomem *)spriv->channel -
+ (char __iomem *)devpriv->iobase));
+
+ return spriv;
+}
+
static int jr3_pci_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
- int result;
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- int i;
+ static const struct jr3_pci_board *board = NULL;
struct jr3_pci_dev_private *devpriv;
+ struct jr3_pci_subdev_private *spriv;
+ struct comedi_subdevice *s;
+ int ret;
+ int i;
if (sizeof(struct jr3_channel) != 0xc00) {
dev_err(dev->class_dev,
@@ -639,106 +692,56 @@ static int jr3_pci_auto_attach(struct comedi_device *dev,
return -EINVAL;
}
+ 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;
init_timer(&devpriv->timer);
- switch (pcidev->device) {
- case PCI_DEVICE_ID_JR3_1_CHANNEL:
- case PCI_DEVICE_ID_JR3_1_CHANNEL_NEW:
- devpriv->n_channels = 1;
- break;
- case PCI_DEVICE_ID_JR3_2_CHANNEL:
- devpriv->n_channels = 2;
- break;
- case PCI_DEVICE_ID_JR3_3_CHANNEL:
- devpriv->n_channels = 3;
- break;
- case PCI_DEVICE_ID_JR3_4_CHANNEL:
- devpriv->n_channels = 4;
- break;
- default:
- dev_err(dev->class_dev, "jr3_pci: pci %s not supported\n",
- pci_name(pcidev));
- return -EINVAL;
- break;
- }
- result = comedi_pci_enable(dev);
- if (result)
- return result;
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
devpriv->iobase = pci_ioremap_bar(pcidev, 0);
if (!devpriv->iobase)
return -ENOMEM;
- result = comedi_alloc_subdevices(dev, devpriv->n_channels);
- if (result)
- return result;
+ ret = comedi_alloc_subdevices(dev, board->n_subdevs);
+ if (ret)
+ return ret;
dev->open = jr3_pci_open;
- for (i = 0; i < devpriv->n_channels; i++) {
- dev->subdevices[i].type = COMEDI_SUBD_AI;
- dev->subdevices[i].subdev_flags = SDF_READABLE | SDF_GROUND;
- dev->subdevices[i].n_chan = 8 * 7 + 2;
- dev->subdevices[i].insn_read = jr3_pci_ai_insn_read;
- dev->subdevices[i].private =
- kzalloc(sizeof(struct jr3_pci_subdev_private),
- GFP_KERNEL);
- if (dev->subdevices[i].private) {
- struct jr3_pci_subdev_private *p;
- int j;
-
- p = dev->subdevices[i].private;
- p->channel = &devpriv->iobase->channel[i].data;
- dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n",
- p->channel, devpriv->iobase,
- ((char __iomem *)p->channel -
- (char __iomem *)devpriv->iobase));
- p->channel_no = i;
- for (j = 0; j < 8; j++) {
- int k;
-
- p->range[j].length = 1;
- p->range[j].range.min = -1000000;
- p->range[j].range.max = 1000000;
- for (k = 0; k < 7; k++) {
- p->range_table_list[j + k * 8] =
- (struct comedi_lrange *)&p->
- range[j];
- p->maxdata_list[j + k * 8] = 0x7fff;
- }
- }
- p->range[8].length = 1;
- p->range[8].range.min = 0;
- p->range[8].range.max = 65536;
-
- p->range_table_list[56] =
- (struct comedi_lrange *)&p->range[8];
- p->range_table_list[57] =
- (struct comedi_lrange *)&p->range[8];
- p->maxdata_list[56] = 0xffff;
- p->maxdata_list[57] = 0xffff;
- /* Channel specific range and maxdata */
- dev->subdevices[i].range_table = NULL;
- dev->subdevices[i].range_table_list =
- p->range_table_list;
- dev->subdevices[i].maxdata = 0;
- dev->subdevices[i].maxdata_list = p->maxdata_list;
+ 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) {
+ /* Channel specific range and maxdata */
+ s->range_table_list = spriv->range_table_list;
+ s->maxdata_list = spriv->maxdata_list;
}
}
/* Reset DSP card */
writel(0, &devpriv->iobase->channel[0].reset);
- result = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev,
- "comedi/jr3pci.idm",
- jr3_download_firmware, 0);
- dev_dbg(dev->class_dev, "Firmare load %d\n", result);
-
- if (result < 0)
- return result;
+ ret = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev,
+ "comedi/jr3pci.idm",
+ jr3_download_firmware, 0);
+ dev_dbg(dev->class_dev, "Firmare load %d\n", ret);
+ if (ret < 0)
+ return ret;
/*
* TODO: use firmware to load preferred offset tables. Suggested
* format:
@@ -761,11 +764,12 @@ static int jr3_pci_auto_attach(struct comedi_device *dev,
}
/* Start card timer */
- for (i = 0; i < devpriv->n_channels; i++) {
- struct jr3_pci_subdev_private *p = dev->subdevices[i].private;
+ for (i = 0; i < dev->n_subdevices; i++) {
+ s = &dev->subdevices[i];
+ spriv = s->private;
- p->next_time_min = jiffies + msecs_to_jiffies(500);
- p->next_time_max = jiffies + msecs_to_jiffies(2000);
+ spriv->next_time_min = jiffies + msecs_to_jiffies(500);
+ spriv->next_time_max = jiffies + msecs_to_jiffies(2000);
}
devpriv->timer.data = (unsigned long)dev;
@@ -773,21 +777,16 @@ static int jr3_pci_auto_attach(struct comedi_device *dev,
devpriv->timer.expires = jiffies + msecs_to_jiffies(1000);
add_timer(&devpriv->timer);
- return result;
+ return 0;
}
static void jr3_pci_detach(struct comedi_device *dev)
{
- int i;
struct jr3_pci_dev_private *devpriv = dev->private;
if (devpriv) {
del_timer_sync(&devpriv->timer);
- if (dev->subdevices) {
- for (i = 0; i < devpriv->n_channels; i++)
- kfree(dev->subdevices[i].private);
- }
if (devpriv->iobase)
iounmap(devpriv->iobase);
}
@@ -807,12 +806,12 @@ static int jr3_pci_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &jr3_pci_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) },
+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);
diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/staging/comedi/drivers/jr3_pci.h
index 3317f7a04c4..20478ae8fad 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.h
+++ b/drivers/staging/comedi/drivers/jr3_pci.h
@@ -671,11 +671,11 @@ struct jr3_channel {
struct jr3_t {
struct {
- u32 program_low[0x4000]; /* 0x00000 - 0x10000 */
+ u32 program_lo[0x4000]; /* 0x00000 - 0x10000 */
struct jr3_channel data; /* 0x10000 - 0x10c00 */
char pad2[0x30000 - 0x00c00]; /* 0x10c00 - 0x40000 */
- u32 program_high[0x8000]; /* 0x40000 - 0x60000 */
- u32 reset; /* 0x60000 - 0x60004 */
+ u32 program_hi[0x8000]; /* 0x40000 - 0x60000 */
+ u32 reset; /* 0x60000 - 0x60004 */
char pad3[0x20000 - 0x00004]; /* 0x60004 - 0x80000 */
} channel[4];
};
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index 15589f62a61..ec43c38958d 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -1,92 +1,113 @@
/*
- comedi/drivers/ke_counter.c
- Comedi driver for Kolter-Electronic PCI Counter 1 Card
-
- 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.
-*/
-/*
-Driver: ke_counter
-Description: Driver for Kolter Electronic Counter Card
-Devices: [Kolter Electronic] PCI Counter Card (ke_counter)
-Author: Michael Hillmann
-Updated: Mon, 14 Apr 2008 15:42:42 +0100
-Status: tested
-
-Configuration Options: not applicable, uses PCI auto config
+ * ke_counter.c
+ * Comedi driver for Kolter-Electronic PCI Counter 1 Card
+ *
+ * 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.
+ */
-This driver is a simple driver to read the counter values from
-Kolter Electronic PCI Counter Card.
-*/
+/*
+ * Driver: ke_counter
+ * Description: Driver for Kolter Electronic Counter Card
+ * Devices: (Kolter Electronic) PCI Counter Card [ke_counter]
+ * Author: Michael Hillmann
+ * Updated: Mon, 14 Apr 2008 15:42:42 +0100
+ * Status: tested
+ *
+ * Configuration Options: not applicable, uses PCI auto config
+ */
#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
-#define CNT_CARD_DEVICE_ID 0x0014
+/*
+ * PCI BAR 0 Register I/O map
+ */
+#define KE_RESET_REG(x) (0x00 + ((x) * 0x20))
+#define KE_LATCH_REG(x) (0x00 + ((x) * 0x20))
+#define KE_LSB_REG(x) (0x04 + ((x) * 0x20))
+#define KE_MID_REG(x) (0x08 + ((x) * 0x20))
+#define KE_MSB_REG(x) (0x0c + ((x) * 0x20))
+#define KE_SIGN_REG(x) (0x10 + ((x) * 0x20))
+#define KE_OSC_SEL_REG 0xf8
+#define KE_OSC_SEL_EXT (1 << 0)
+#define KE_OSC_SEL_4MHZ (2 << 0)
+#define KE_OSC_SEL_20MHZ (3 << 0)
+#define KE_DO_REG 0xfc
+
+static int ke_counter_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
+ int i;
-/*-- counter write ----------------------------------------------------------*/
+ for (i = 0; i < insn->n; i++) {
+ val = data[0];
-/* This should be used only for resetting the counters; maybe it is better
- to make a special command 'reset'. */
-static int cnt_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
-{
- int chan = CR_CHAN(insn->chanspec);
-
- outb((unsigned char)((data[0] >> 24) & 0xff),
- dev->iobase + chan * 0x20 + 0x10);
- outb((unsigned char)((data[0] >> 16) & 0xff),
- dev->iobase + chan * 0x20 + 0x0c);
- outb((unsigned char)((data[0] >> 8) & 0xff),
- dev->iobase + chan * 0x20 + 0x08);
- outb((unsigned char)((data[0] >> 0) & 0xff),
- dev->iobase + chan * 0x20 + 0x04);
-
- /* return the number of samples written */
- return 1;
-}
+ /* Order matters */
+ outb((val >> 24) & 0xff, dev->iobase + KE_SIGN_REG(chan));
+ outb((val >> 16) & 0xff, dev->iobase + KE_MSB_REG(chan));
+ outb((val >> 8) & 0xff, dev->iobase + KE_MID_REG(chan));
+ outb((val >> 0) & 0xff, dev->iobase + KE_LSB_REG(chan));
+ }
-/*-- counter read -----------------------------------------------------------*/
+ return insn->n;
+}
-static int cnt_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
+static int ke_counter_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- unsigned char a0, a1, a2, a3, a4;
- int chan = CR_CHAN(insn->chanspec);
- int result;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
+ int i;
- a0 = inb(dev->iobase + chan * 0x20);
- a1 = inb(dev->iobase + chan * 0x20 + 0x04);
- a2 = inb(dev->iobase + chan * 0x20 + 0x08);
- a3 = inb(dev->iobase + chan * 0x20 + 0x0c);
- a4 = inb(dev->iobase + chan * 0x20 + 0x10);
+ for (i = 0; i < insn->n; i++) {
+ /* Order matters */
+ inb(dev->iobase + KE_LATCH_REG(chan));
- result = (a1 + (a2 * 256) + (a3 * 65536));
- if (a4 > 0)
- result = result - s->maxdata;
+ val = inb(dev->iobase + KE_LSB_REG(chan));
+ val |= (inb(dev->iobase + KE_MID_REG(chan)) << 8);
+ val |= (inb(dev->iobase + KE_MSB_REG(chan)) << 16);
+ val |= (inb(dev->iobase + KE_SIGN_REG(chan)) << 24);
- *data = (unsigned int)result;
+ data[i] = val;
+ }
- /* return the number of samples read */
- return 1;
+ return insn->n;
}
-static int cnt_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+static int ke_counter_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (comedi_dio_update_state(s, data))
+ outb(s->state, dev->iobase + KE_DO_REG);
+
+ data[1] = s->state;
+
+ return insn->n;
+}
+
+static int ke_counter_auto_attach(struct comedi_device *dev,
+ unsigned long context_unused)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct comedi_subdevice *s;
@@ -97,30 +118,32 @@ static int cnt_auto_attach(struct comedi_device *dev,
return ret;
dev->iobase = pci_resource_start(pcidev, 0);
- ret = comedi_alloc_subdevices(dev, 1);
+ ret = comedi_alloc_subdevices(dev, 2);
if (ret)
return ret;
s = &dev->subdevices[0];
- dev->read_subdev = s;
-
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ;
- s->n_chan = 3;
- s->maxdata = 0x00ffffff;
- s->insn_read = cnt_rinsn;
- s->insn_write = cnt_winsn;
-
- /* select 20MHz clock */
- outb(3, dev->iobase + 248);
-
- /* reset all counters */
- outb(0, dev->iobase);
- outb(0, dev->iobase + 0x20);
- outb(0, dev->iobase + 0x40);
-
- dev_info(dev->class_dev, "%s: %s attached\n",
- dev->driver->driver_name, dev->board_name);
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 3;
+ s->maxdata = 0x01ffffff;
+ s->range_table = &range_unknown;
+ s->insn_read = ke_counter_insn_read;
+ s->insn_write = ke_counter_insn_write;
+
+ s = &dev->subdevices[1];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 3;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = ke_counter_do_insn_bits;
+
+ outb(KE_OSC_SEL_20MHZ, dev->iobase + KE_OSC_SEL_REG);
+
+ outb(0, dev->iobase + KE_RESET_REG(0));
+ outb(0, dev->iobase + KE_RESET_REG(1));
+ outb(0, dev->iobase + KE_RESET_REG(2));
return 0;
}
@@ -128,7 +151,7 @@ static int cnt_auto_attach(struct comedi_device *dev,
static struct comedi_driver ke_counter_driver = {
.driver_name = "ke_counter",
.module = THIS_MODULE,
- .auto_attach = cnt_auto_attach,
+ .auto_attach = ke_counter_auto_attach,
.detach = comedi_pci_disable,
};
@@ -139,8 +162,8 @@ static int ke_counter_pci_probe(struct pci_dev *dev,
id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(ke_counter_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) },
+static const struct pci_device_id ke_counter_pci_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, 0x0014) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, ke_counter_pci_table);
@@ -154,5 +177,5 @@ static struct pci_driver ke_counter_pci_driver = {
module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for Kolter Electronic Counter Card");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index 3d12e913592..25ce2f78db8 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -328,13 +328,12 @@ static const struct me4000_board me4000_boards[] = {
};
static const struct comedi_lrange me4000_ai_range = {
- 4,
- {
- UNI_RANGE(2.5),
- UNI_RANGE(10),
- BIP_RANGE(2.5),
- BIP_RANGE(10),
- }
+ 4, {
+ UNI_RANGE(2.5),
+ UNI_RANGE(10),
+ BIP_RANGE(2.5),
+ BIP_RANGE(10)
+ }
};
#define FIRMWARE_NOT_AVAILABLE 1
@@ -599,67 +598,35 @@ static int me4000_ai_cancel(struct comedi_device *dev,
return 0;
}
-static int ai_check_chanlist(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd)
+static int me4000_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
{
- const struct me4000_board *thisboard = comedi_board(dev);
- int aref;
+ const struct me4000_board *board = comedi_board(dev);
+ unsigned int max_diff_chan = board->ai_diff_nchan;
+ unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
int i;
- /* Check whether a channel list is available */
- if (!cmd->chanlist_len) {
- dev_err(dev->class_dev, "No channel list available\n");
- return -EINVAL;
- }
-
- /* Check the channel list size */
- if (cmd->chanlist_len > ME4000_AI_CHANNEL_LIST_COUNT) {
- dev_err(dev->class_dev, "Channel list is to large\n");
- return -EINVAL;
- }
-
- /* Check the pointer */
- if (!cmd->chanlist) {
- dev_err(dev->class_dev, "NULL pointer to channel list\n");
- return -EFAULT;
- }
-
- /* Check whether aref is equal for all entries */
- aref = CR_AREF(cmd->chanlist[0]);
for (i = 0; i < cmd->chanlist_len; i++) {
- if (CR_AREF(cmd->chanlist[i]) != aref) {
- dev_err(dev->class_dev,
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+ unsigned int range = CR_RANGE(cmd->chanlist[i]);
+ unsigned int aref = CR_AREF(cmd->chanlist[i]);
+
+ if (aref != aref0) {
+ dev_dbg(dev->class_dev,
"Mode is not equal for all entries\n");
return -EINVAL;
}
- }
- /* Check whether channels are available for this ending */
- if (aref == SDF_DIFF) {
- for (i = 0; i < cmd->chanlist_len; i++) {
- if (CR_CHAN(cmd->chanlist[i]) >=
- thisboard->ai_diff_nchan) {
- dev_err(dev->class_dev,
+ if (aref == SDF_DIFF) {
+ if (chan >= max_diff_chan) {
+ dev_dbg(dev->class_dev,
"Channel number to high\n");
return -EINVAL;
}
- }
- } else {
- for (i = 0; i < cmd->chanlist_len; i++) {
- if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai_nchan) {
- dev_err(dev->class_dev,
- "Channel number to high\n");
- return -EINVAL;
- }
- }
- }
- /* Check if bipolar is set for all entries when in differential mode */
- if (aref == SDF_DIFF) {
- for (i = 0; i < cmd->chanlist_len; i++) {
- if (CR_RANGE(cmd->chanlist[i]) != 1 &&
- CR_RANGE(cmd->chanlist[i]) != 2) {
- dev_err(dev->class_dev,
+ if (!comedi_range_is_bipolar(s, range)) {
+ dev_dbg(dev->class_dev,
"Bipolar is not selected in differential mode\n");
return -EINVAL;
}
@@ -935,22 +902,13 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
err |= -EINVAL;
}
- if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_NONE) {
- } else if (cmd->stop_src == TRIG_COUNT &&
- cmd->scan_end_src == TRIG_NONE) {
- } else if (cmd->stop_src == TRIG_NONE &&
- cmd->scan_end_src == TRIG_COUNT) {
- } else if (cmd->stop_src == TRIG_COUNT &&
- cmd->scan_end_src == TRIG_COUNT) {
- } else {
- err |= -EINVAL;
- }
-
if (err)
return 2;
/* Step 3: check if arguments are trivially valid */
+ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+
if (cmd->chanlist_len < 1) {
cmd->chanlist_len = 1;
err |= -EINVAL;
@@ -1092,10 +1050,11 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
if (err)
return 4;
- /*
- * Stage 5. Check the channel list.
- */
- if (ai_check_chanlist(dev, s, cmd))
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= me4000_ai_check_chanlist(dev, s, cmd);
+
+ if (err)
return 5;
return 0;
@@ -1105,7 +1064,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
{
unsigned int tmp;
struct comedi_device *dev = dev_id;
- struct comedi_subdevice *s = &dev->subdevices[0];
+ struct comedi_subdevice *s = dev->read_subdev;
int i;
int c = 0;
unsigned int lval;
@@ -1113,15 +1072,6 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
if (!dev->attached)
return IRQ_NONE;
- /* Reset all events */
- s->async->events = 0;
-
- /* Check if irq number is right */
- if (irq != dev->irq) {
- dev_err(dev->class_dev, "Incorrect interrupt num: %d\n", irq);
- return IRQ_HANDLED;
- }
-
if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) &
ME4000_IRQ_STATUS_BIT_AI_HF) {
/* Read status register to find out what happened */
@@ -1174,7 +1124,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
lval ^= 0x8000;
- if (!comedi_buf_put(s->async, lval)) {
+ if (!comedi_buf_put(s, lval)) {
/*
* Buffer overflow, so stop conversion
* and disable all interrupts
@@ -1219,7 +1169,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF;
lval ^= 0x8000;
- if (!comedi_buf_put(s->async, lval)) {
+ if (!comedi_buf_put(s, lval)) {
dev_err(dev->class_dev, "Buffer overflow\n");
s->async->events |= COMEDI_CB_OVERFLOW;
break;
@@ -1402,6 +1352,7 @@ static int me4000_cnt_insn_config(struct comedi_device *dev,
unsigned int *data)
{
struct me4000_info *info = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
int err;
switch (data[0]) {
@@ -1409,16 +1360,17 @@ static int me4000_cnt_insn_config(struct comedi_device *dev,
if (insn->n != 1)
return -EINVAL;
- err = i8254_load(info->timer_regbase, 0, insn->chanspec, 0,
- I8254_MODE0 | I8254_BINARY);
+ err = i8254_set_mode(info->timer_regbase, 0, chan,
+ I8254_MODE0 | I8254_BINARY);
if (err)
return err;
+ i8254_write(info->timer_regbase, 0, chan, 0);
break;
case GPCT_SET_OPERATION:
if (insn->n != 2)
return -EINVAL;
- err = i8254_set_mode(info->timer_regbase, 0, insn->chanspec,
+ err = i8254_set_mode(info->timer_regbase, 0, chan,
(data[1] << 1) | I8254_BINARY);
if (err)
return err;
@@ -1505,6 +1457,13 @@ static int me4000_auto_attach(struct comedi_device *dev,
me4000_reset(dev);
+ if (pcidev->irq > 0) {
+ result = request_irq(pcidev->irq, me4000_ai_isr, IRQF_SHARED,
+ dev->board_name, dev);
+ if (result == 0)
+ dev->irq = pcidev->irq;
+ }
+
result = comedi_alloc_subdevices(dev, 4);
if (result)
return result;
@@ -1525,22 +1484,12 @@ static int me4000_auto_attach(struct comedi_device *dev,
s->range_table = &me4000_ai_range;
s->insn_read = me4000_ai_insn_read;
- if (pcidev->irq > 0) {
- if (request_irq(pcidev->irq, me4000_ai_isr,
- IRQF_SHARED, dev->board_name, dev)) {
- dev_warn(dev->class_dev,
- "request_irq failed\n");
- } else {
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->cancel = me4000_ai_cancel;
- s->do_cmdtest = me4000_ai_do_cmd_test;
- s->do_cmd = me4000_ai_do_cmd;
-
- dev->irq = pcidev->irq;
- }
- } else {
- dev_warn(dev->class_dev, "No interrupt available\n");
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->cancel = me4000_ai_cancel;
+ s->do_cmdtest = me4000_ai_do_cmd_test;
+ s->do_cmd = me4000_ai_do_cmd;
}
} else {
s->type = COMEDI_SUBD_UNUSED;
@@ -1635,7 +1584,7 @@ static int me4000_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &me4000_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = {
+static const struct pci_device_id me4000_pci_table[] = {
{ PCI_VDEVICE(MEILHAUS, 0x4650), BOARD_ME4650 },
{ PCI_VDEVICE(MEILHAUS, 0x4660), BOARD_ME4660 },
{ PCI_VDEVICE(MEILHAUS, 0x4661), BOARD_ME4660I },
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index 24ec9ef9b1a..0ff126b1fdf 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -248,6 +248,20 @@ static int me_dio_insn_bits(struct comedi_device *dev,
return insn->n;
}
+static int me_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct me_private_data *dev_private = dev->private;
+ unsigned int status;
+
+ status = readw(dev_private->me_regbase + ME_STATUS);
+ if ((status & 0x0004) == 0)
+ return 0;
+ return -EBUSY;
+}
+
static int me_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -258,7 +272,7 @@ static int me_ai_insn_read(struct comedi_device *dev,
unsigned int rang = CR_RANGE(insn->chanspec);
unsigned int aref = CR_AREF(insn->chanspec);
unsigned short val;
- int i;
+ int ret;
/* stop any running conversion */
dev_private->control_1 &= 0xFFFC;
@@ -290,19 +304,14 @@ static int me_ai_insn_read(struct comedi_device *dev,
readw(dev_private->me_regbase + ME_ADC_START);
/* wait for ADC fifo not empty flag */
- for (i = 100000; i > 0; i--)
- if (!(readw(dev_private->me_regbase + ME_STATUS) & 0x0004))
- break;
+ ret = comedi_timeout(dev, s, insn, me_ai_eoc, 0);
+ if (ret)
+ return ret;
/* get value from ADC fifo */
- if (i) {
- val = readw(dev_private->me_regbase + ME_READ_AD_FIFO);
- val = (val ^ 0x800) & 0x0fff;
- data[0] = val;
- } else {
- dev_err(dev->class_dev, "Cannot get single value\n");
- return -EIO;
- }
+ val = readw(dev_private->me_regbase + ME_READ_AD_FIFO);
+ val = (val ^ 0x800) & 0x0fff;
+ data[0] = val;
/* stop any running conversion */
dev_private->control_1 &= 0xFFFC;
@@ -542,9 +551,6 @@ static int me_auto_attach(struct comedi_device *dev,
s->insn_bits = me_dio_insn_bits;
s->insn_config = me_dio_insn_config;
- dev_info(dev->class_dev, "%s: %s attached\n",
- dev->driver->driver_name, dev->board_name);
-
return 0;
}
@@ -576,7 +582,7 @@ static int me_daq_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &me_daq_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(me_daq_pci_table) = {
+static const struct pci_device_id me_daq_pci_table[] = {
{ PCI_VDEVICE(MEILHAUS, 0x2600), BOARD_ME2600 },
{ PCI_VDEVICE(MEILHAUS, 0x2000), BOARD_ME2000 },
{ 0 }
diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c
new file mode 100644
index 00000000000..a4f7d6f138d
--- /dev/null
+++ b/drivers/staging/comedi/drivers/mf6x4.c
@@ -0,0 +1,351 @@
+/*
+ * comedi/drivers/mf6x4.c
+ * Driver for Humusoft MF634 and MF624 Data acquisition cards
+ *
+ * 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.
+ */
+/*
+ * Driver: mf6x4
+ * Description: Humusoft MF634 and MF624 Data acquisition card driver
+ * Devices: Humusoft MF634, Humusoft MF624
+ * Author: Rostislav Lisovy <lisovy@gmail.com>
+ * Status: works
+ * Updated:
+ * Configuration Options: none
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include "../comedidev.h"
+
+/* Registers present in BAR0 memory region */
+#define MF624_GPIOC_R 0x54
+
+#define MF6X4_GPIOC_EOLC /* End Of Last Conversion */ (1 << 17)
+#define MF6X4_GPIOC_LDAC /* Load DACs */ (1 << 23)
+#define MF6X4_GPIOC_DACEN (1 << 26)
+
+/* BAR1 registers */
+#define MF6X4_DIN_R 0x10
+#define MF6X4_DIN_M 0xff
+#define MF6X4_DOUT_R 0x10
+#define MF6X4_DOUT_M 0xff
+
+#define MF6X4_ADSTART_R 0x20
+#define MF6X4_ADDATA_R 0x00
+#define MF6X4_ADCTRL_R 0x00
+#define MF6X4_ADCTRL_M 0xff
+
+#define MF6X4_DA0_R 0x20
+#define MF6X4_DA1_R 0x22
+#define MF6X4_DA2_R 0x24
+#define MF6X4_DA3_R 0x26
+#define MF6X4_DA4_R 0x28
+#define MF6X4_DA5_R 0x2a
+#define MF6X4_DA6_R 0x2c
+#define MF6X4_DA7_R 0x2e
+/* Map DAC cahnnel id to real HW-dependent offset value */
+#define MF6X4_DAC_R(x) (0x20 + ((x) * 2))
+#define MF6X4_DA_M 0x3fff
+
+/* BAR2 registers */
+#define MF634_GPIOC_R 0x68
+
+enum mf6x4_boardid {
+ BOARD_MF634,
+ BOARD_MF624,
+};
+
+struct mf6x4_board {
+ const char *name;
+ unsigned int bar_nums[3]; /* We need to keep track of the
+ order of BARs used by the cards */
+};
+
+static const struct mf6x4_board mf6x4_boards[] = {
+ [BOARD_MF634] = {
+ .name = "mf634",
+ .bar_nums = {0, 2, 3},
+ },
+ [BOARD_MF624] = {
+ .name = "mf624",
+ .bar_nums = {0, 2, 4},
+ },
+};
+
+struct mf6x4_private {
+ /*
+ * Documentation for both MF634 and MF624 describes registers
+ * present in BAR0, 1 and 2 regions.
+ * The real (i.e. in HW) BAR numbers are different for MF624
+ * and MF634 yet we will call them 0, 1, 2
+ */
+ void __iomem *bar0_mem;
+ void __iomem *bar1_mem;
+ void __iomem *bar2_mem;
+
+ /*
+ * This configuration register has the same function and fields
+ * for both cards however it lies in different BARs on different
+ * offsets -- this variable makes the access easier
+ */
+ void __iomem *gpioc_R;
+
+ /* DAC value cache -- used for insn_read function */
+ int ao_readback[8];
+};
+
+static int mf6x4_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct mf6x4_private *devpriv = dev->private;
+
+ data[1] = ioread16(devpriv->bar1_mem + MF6X4_DIN_R) & MF6X4_DIN_M;
+
+ return insn->n;
+}
+
+static int mf6x4_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct mf6x4_private *devpriv = dev->private;
+
+ if (comedi_dio_update_state(s, data))
+ iowrite16(s->state & MF6X4_DOUT_M,
+ devpriv->bar1_mem + MF6X4_DOUT_R);
+
+ data[1] = s->state;
+
+ return insn->n;
+}
+
+static int mf6x4_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct mf6x4_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = ioread32(devpriv->gpioc_R);
+ if (status & MF6X4_GPIOC_EOLC)
+ return 0;
+ return -EBUSY;
+}
+
+static int mf6x4_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct mf6x4_private *devpriv = dev->private;
+ int chan = CR_CHAN(insn->chanspec);
+ int ret;
+ int i;
+ int d;
+
+ /* Set the ADC channel number in the scan list */
+ iowrite16((1 << chan) & MF6X4_ADCTRL_M,
+ devpriv->bar1_mem + MF6X4_ADCTRL_R);
+
+ for (i = 0; i < insn->n; i++) {
+ /* Trigger ADC conversion by reading ADSTART */
+ ioread16(devpriv->bar1_mem + MF6X4_ADSTART_R);
+
+ ret = comedi_timeout(dev, s, insn, mf6x4_ai_eoc, 0);
+ if (ret)
+ return ret;
+
+ /* Read the actual value */
+ d = ioread16(devpriv->bar1_mem + MF6X4_ADDATA_R);
+ d &= s->maxdata;
+ data[i] = d;
+ }
+
+ iowrite16(0x0, devpriv->bar1_mem + MF6X4_ADCTRL_R);
+
+ return insn->n;
+}
+
+static int mf6x4_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct mf6x4_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ uint32_t gpioc;
+ int i;
+
+ /* Enable instantaneous update of converters outputs + Enable DACs */
+ gpioc = ioread32(devpriv->gpioc_R);
+ iowrite32((gpioc & ~MF6X4_GPIOC_LDAC) | MF6X4_GPIOC_DACEN,
+ devpriv->gpioc_R);
+
+ for (i = 0; i < insn->n; i++) {
+ iowrite16(data[i] & MF6X4_DA_M,
+ devpriv->bar1_mem + MF6X4_DAC_R(chan));
+
+ devpriv->ao_readback[chan] = data[i];
+ }
+
+ return insn->n;
+}
+
+static int mf6x4_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct mf6x4_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
+
+ return insn->n;
+}
+
+static int mf6x4_auto_attach(struct comedi_device *dev, unsigned long context)
+{
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ const struct mf6x4_board *board = NULL;
+ struct mf6x4_private *devpriv;
+ struct comedi_subdevice *s;
+ int ret;
+
+ if (context < ARRAY_SIZE(mf6x4_boards))
+ board = &mf6x4_boards[context];
+ else
+ return -ENODEV;
+
+ dev->board_ptr = board;
+ dev->board_name = board->name;
+
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
+
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+ if (!devpriv)
+ return -ENOMEM;
+
+ devpriv->bar0_mem = pci_ioremap_bar(pcidev, board->bar_nums[0]);
+ if (!devpriv->bar0_mem)
+ return -ENODEV;
+
+ devpriv->bar1_mem = pci_ioremap_bar(pcidev, board->bar_nums[1]);
+ if (!devpriv->bar1_mem)
+ return -ENODEV;
+
+ devpriv->bar2_mem = pci_ioremap_bar(pcidev, board->bar_nums[2]);
+ if (!devpriv->bar2_mem)
+ return -ENODEV;
+
+ if (board == &mf6x4_boards[BOARD_MF634])
+ devpriv->gpioc_R = devpriv->bar2_mem + MF634_GPIOC_R;
+ else
+ devpriv->gpioc_R = devpriv->bar0_mem + MF624_GPIOC_R;
+
+
+ ret = comedi_alloc_subdevices(dev, 4);
+ if (ret)
+ return ret;
+
+ /* ADC */
+ s = &dev->subdevices[0];
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND;
+ s->n_chan = 8;
+ s->maxdata = 0x3fff; /* 14 bits ADC */
+ s->range_table = &range_bipolar10;
+ s->insn_read = mf6x4_ai_insn_read;
+
+ /* DAC */
+ s = &dev->subdevices[1];
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 8;
+ s->maxdata = 0x3fff; /* 14 bits DAC */
+ s->range_table = &range_bipolar10;
+ s->insn_write = mf6x4_ao_insn_write;
+ s->insn_read = mf6x4_ao_insn_read;
+
+ /* DIN */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = mf6x4_di_insn_bits;
+
+ /* DOUT */
+ s = &dev->subdevices[3];
+ 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 = mf6x4_do_insn_bits;
+
+ return 0;
+}
+
+static void mf6x4_detach(struct comedi_device *dev)
+{
+ struct mf6x4_private *devpriv = dev->private;
+
+ if (devpriv->bar0_mem)
+ iounmap(devpriv->bar0_mem);
+ if (devpriv->bar1_mem)
+ iounmap(devpriv->bar1_mem);
+ if (devpriv->bar2_mem)
+ iounmap(devpriv->bar2_mem);
+
+ comedi_pci_disable(dev);
+}
+
+static struct comedi_driver mf6x4_driver = {
+ .driver_name = "mf6x4",
+ .module = THIS_MODULE,
+ .auto_attach = mf6x4_auto_attach,
+ .detach = mf6x4_detach,
+};
+
+static int mf6x4_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return comedi_pci_auto_config(dev, &mf6x4_driver, id->driver_data);
+}
+
+static const struct pci_device_id mf6x4_pci_table[] = {
+ { PCI_VDEVICE(HUMUSOFT, 0x0634), BOARD_MF634 },
+ { PCI_VDEVICE(HUMUSOFT, 0x0624), BOARD_MF624 },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, mf6x4_pci_table);
+
+static struct pci_driver mf6x4_pci_driver = {
+ .name = "mf6x4",
+ .id_table = mf6x4_pci_table,
+ .probe = mf6x4_pci_probe,
+ .remove = comedi_pci_auto_unconfig,
+};
+
+module_comedi_pci_driver(mf6x4_driver, mf6x4_pci_driver);
+
+MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");
+MODULE_DESCRIPTION("Comedi MF634 and MF624 DAQ cards driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index 35cb4ace797..19c029acbc9 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -288,7 +288,6 @@ void mite_dma_arm(struct mite_channel *mite_chan)
int chor;
unsigned long flags;
- MDPRINTK("mite_dma_arm ch%i\n", mite_chan->channel);
/*
* memory barrier is intended to insure any twiddling with the buffer
* is done before writing to the mite to arm dma transfer
@@ -308,8 +307,9 @@ EXPORT_SYMBOL_GPL(mite_dma_arm);
/**************************************/
int mite_buf_change(struct mite_dma_descriptor_ring *ring,
- struct comedi_async *async)
+ struct comedi_subdevice *s)
{
+ struct comedi_async *async = s->async;
unsigned int n_links;
int i;
@@ -329,14 +329,12 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring,
n_links = async->prealloc_bufsz >> PAGE_SHIFT;
- MDPRINTK("ring->hw_dev=%p, n_links=0x%04x\n", ring->hw_dev, n_links);
-
ring->descriptors =
dma_alloc_coherent(ring->hw_dev,
n_links * sizeof(struct mite_dma_descriptor),
&ring->descriptors_dma_addr, GFP_KERNEL);
if (!ring->descriptors) {
- dev_err(async->subdevice->device->class_dev,
+ dev_err(s->device->class_dev,
"mite: ring buffer allocation failed\n");
return -ENOMEM;
}
@@ -345,7 +343,7 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring,
for (i = 0; i < n_links; i++) {
ring->descriptors[i].count = cpu_to_le32(PAGE_SIZE);
ring->descriptors[i].addr =
- cpu_to_le32(async->buf_page_list[i].dma_addr);
+ cpu_to_le32(async->buf_map->page_list[i].dma_addr);
ring->descriptors[i].next =
cpu_to_le32(ring->descriptors_dma_addr + (i +
1) *
@@ -368,8 +366,6 @@ void mite_prep_dma(struct mite_channel *mite_chan,
unsigned int chor, chcr, mcr, dcr, lkcr;
struct mite_struct *mite = mite_chan->mite;
- MDPRINTK("mite_prep_dma ch%i\n", mite_chan->channel);
-
/* reset DMA and FIFO */
chor = CHOR_DMARESET | CHOR_FRESET;
writel(chor, mite->mite_io_addr + MITE_CHOR(mite_chan->channel));
@@ -448,8 +444,6 @@ void mite_prep_dma(struct mite_channel *mite_chan,
/* starting address for link chaining */
writel(mite_chan->ring->descriptors_dma_addr,
mite->mite_io_addr + MITE_LKAR(mite_chan->channel));
-
- MDPRINTK("exit mite_prep_dma\n");
}
EXPORT_SYMBOL_GPL(mite_prep_dma);
@@ -515,8 +509,6 @@ unsigned mite_dma_tcr(struct mite_channel *mite_chan)
lkar = readl(mite->mite_io_addr + MITE_LKAR(mite_chan->channel));
tcr = readl(mite->mite_io_addr + MITE_TCR(mite_chan->channel));
- MDPRINTK("mite_dma_tcr ch%i, lkar=0x%08x tcr=%d\n", mite_chan->channel,
- lkar, tcr);
return tcr;
}
@@ -534,20 +526,20 @@ void mite_dma_disarm(struct mite_channel *mite_chan)
EXPORT_SYMBOL_GPL(mite_dma_disarm);
int mite_sync_input_dma(struct mite_channel *mite_chan,
- struct comedi_async *async)
+ struct comedi_subdevice *s)
{
+ struct comedi_async *async = s->async;
int count;
unsigned int nbytes, old_alloc_count;
- const unsigned bytes_per_scan = cfc_bytes_per_scan(async->subdevice);
old_alloc_count = async->buf_write_alloc_count;
/* write alloc as much as we can */
- comedi_buf_write_alloc(async, async->prealloc_bufsz);
+ comedi_buf_write_alloc(s, async->prealloc_bufsz);
nbytes = mite_bytes_written_to_memory_lb(mite_chan);
if ((int)(mite_bytes_written_to_memory_ub(mite_chan) -
old_alloc_count) > 0) {
- dev_warn(async->subdevice->device->class_dev,
+ dev_warn(s->device->class_dev,
"mite: DMA overwrite of free area\n");
async->events |= COMEDI_CB_OVERFLOW;
return -1;
@@ -559,41 +551,33 @@ int mite_sync_input_dma(struct mite_channel *mite_chan,
if (count <= 0)
return 0;
- comedi_buf_write_free(async, count);
-
- async->scan_progress += count;
- if (async->scan_progress >= bytes_per_scan) {
- async->scan_progress %= bytes_per_scan;
- async->events |= COMEDI_CB_EOS;
- }
+ comedi_buf_write_free(s, count);
+ cfc_inc_scan_progress(s, count);
async->events |= COMEDI_CB_BLOCK;
return 0;
}
EXPORT_SYMBOL_GPL(mite_sync_input_dma);
int mite_sync_output_dma(struct mite_channel *mite_chan,
- struct comedi_async *async)
+ struct comedi_subdevice *s)
{
- int count;
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ u32 stop_count = cmd->stop_arg * cfc_bytes_per_scan(s);
+ unsigned int old_alloc_count = async->buf_read_alloc_count;
u32 nbytes_ub, nbytes_lb;
- unsigned int old_alloc_count;
- u32 stop_count =
- async->cmd.stop_arg * cfc_bytes_per_scan(async->subdevice);
+ int count;
- old_alloc_count = async->buf_read_alloc_count;
/* read alloc as much as we can */
- comedi_buf_read_alloc(async, async->prealloc_bufsz);
+ comedi_buf_read_alloc(s, async->prealloc_bufsz);
nbytes_lb = mite_bytes_read_from_memory_lb(mite_chan);
- if (async->cmd.stop_src == TRIG_COUNT &&
- (int)(nbytes_lb - stop_count) > 0)
+ if (cmd->stop_src == TRIG_COUNT && (int)(nbytes_lb - stop_count) > 0)
nbytes_lb = stop_count;
nbytes_ub = mite_bytes_read_from_memory_ub(mite_chan);
- if (async->cmd.stop_src == TRIG_COUNT &&
- (int)(nbytes_ub - stop_count) > 0)
+ if (cmd->stop_src == TRIG_COUNT && (int)(nbytes_ub - stop_count) > 0)
nbytes_ub = stop_count;
if ((int)(nbytes_ub - old_alloc_count) > 0) {
- dev_warn(async->subdevice->device->class_dev,
- "mite: DMA underrun\n");
+ dev_warn(s->device->class_dev, "mite: DMA underrun\n");
async->events |= COMEDI_CB_OVERFLOW;
return -1;
}
@@ -602,7 +586,7 @@ int mite_sync_output_dma(struct mite_channel *mite_chan,
return 0;
if (count) {
- comedi_buf_read_free(async, count);
+ comedi_buf_read_free(s, count);
async->events |= COMEDI_CB_BLOCK;
}
return 0;
@@ -642,140 +626,6 @@ int mite_done(struct mite_channel *mite_chan)
}
EXPORT_SYMBOL_GPL(mite_done);
-#ifdef DEBUG_MITE
-
-/* names of bits in mite registers */
-
-static const char *const mite_CHOR_strings[] = {
- "start", "cont", "stop", "abort",
- "freset", "clrlc", "clrrb", "clrdone",
- "clr_lpause", "set_lpause", "clr_send_tc",
- "set_send_tc", "12", "13", "14",
- "15", "16", "17", "18",
- "19", "20", "21", "22",
- "23", "24", "25", "26",
- "27", "28", "29", "30",
- "dmareset",
-};
-
-static const char *const mite_CHCR_strings[] = {
- "continue", "ringbuff", "2", "3",
- "4", "5", "6", "7",
- "8", "9", "10", "11",
- "12", "13", "bursten", "fifodis",
- "clr_cont_rb_ie", "set_cont_rb_ie", "clr_lc_ie", "set_lc_ie",
- "clr_drdy_ie", "set_drdy_ie", "clr_mrdy_ie", "set_mrdy_ie",
- "clr_done_ie", "set_done_ie", "clr_sar_ie", "set_sar_ie",
- "clr_linkp_ie", "set_linkp_ie", "clr_dma_ie", "set_dma_ie",
-};
-
-static const char *const mite_MCR_strings[] = {
- "amdevice", "1", "2", "3",
- "4", "5", "portio", "portvxi",
- "psizebyte", "psizehalf (byte & half = word)", "aseqxp1", "11",
- "12", "13", "blocken", "berhand",
- "reqsintlim/reqs0", "reqs1", "reqs2", "rd32",
- "rd512", "rl1", "rl2", "rl8",
- "24", "25", "26", "27",
- "28", "29", "30", "stopen",
-};
-
-static const char *const mite_DCR_strings[] = {
- "amdevice", "1", "2", "3",
- "4", "5", "portio", "portvxi",
- "psizebyte", "psizehalf (byte & half = word)", "aseqxp1", "aseqxp2",
- "aseqxp8", "13", "blocken", "berhand",
- "reqsintlim", "reqs1", "reqs2", "rd32",
- "rd512", "rl1", "rl2", "rl8",
- "23", "24", "25", "27",
- "28", "wsdevc", "wsdevs", "rwdevpack",
-};
-
-static const char *const mite_LKCR_strings[] = {
- "amdevice", "1", "2", "3",
- "4", "5", "portio", "portvxi",
- "psizebyte", "psizehalf (byte & half = word)", "asequp", "aseqdown",
- "12", "13", "14", "berhand",
- "16", "17", "18", "rd32",
- "rd512", "rl1", "rl2", "rl8",
- "24", "25", "26", "27",
- "28", "29", "30", "chngend",
-};
-
-static const char *const mite_CHSR_strings[] = {
- "d.err0", "d.err1", "m.err0", "m.err1",
- "l.err0", "l.err1", "drq0", "drq1",
- "end", "xferr", "operr0", "operr1",
- "stops", "habort", "sabort", "error",
- "16", "conts_rb", "18", "linkc",
- "20", "drdy", "22", "mrdy",
- "24", "done", "26", "sars",
- "28", "lpauses", "30", "int",
-};
-
-static void mite_decode(const char *const *bit_str, unsigned int bits)
-{
- int i;
-
- for (i = 31; i >= 0; i--) {
- if (bits & (1 << i))
- pr_debug(" %s\n", bit_str[i]);
- }
-}
-
-void mite_dump_regs(struct mite_channel *mite_chan)
-{
- void __iomem *mite_io_addr = mite_chan->mite->mite_io_addr;
- unsigned int offset;
- unsigned int value;
- int channel = mite_chan->channel;
-
- pr_debug("mite_dump_regs ch%i\n", channel);
- pr_debug("mite address is =%p\n", mite_io_addr);
-
- offset = MITE_CHOR(channel);
- value = readl(mite_io_addr + offset);
- pr_debug("mite status[CHOR] at 0x%08x =0x%08x\n", offset, value);
- mite_decode(mite_CHOR_strings, value);
- offset = MITE_CHCR(channel);
- value = readl(mite_io_addr + offset);
- pr_debug("mite status[CHCR] at 0x%08x =0x%08x\n", offset, value);
- mite_decode(mite_CHCR_strings, value);
- offset = MITE_TCR(channel);
- value = readl(mite_io_addr + offset);
- pr_debug("mite status[TCR] at 0x%08x =0x%08x\n", offset, value);
- offset = MITE_MCR(channel);
- value = readl(mite_io_addr + offset);
- pr_debug("mite status[MCR] at 0x%08x =0x%08x\n", offset, value);
- mite_decode(mite_MCR_strings, value);
- offset = MITE_MAR(channel);
- value = readl(mite_io_addr + offset);
- pr_debug("mite status[MAR] at 0x%08x =0x%08x\n", offset, value);
- offset = MITE_DCR(channel);
- value = readl(mite_io_addr + offset);
- pr_debug("mite status[DCR] at 0x%08x =0x%08x\n", offset, value);
- mite_decode(mite_DCR_strings, value);
- offset = MITE_DAR(channel);
- value = readl(mite_io_addr + offset);
- pr_debug("mite status[DAR] at 0x%08x =0x%08x\n", offset, value);
- offset = MITE_LKCR(channel);
- value = readl(mite_io_addr + offset);
- pr_debug("mite status[LKCR] at 0x%08x =0x%08x\n", offset, value);
- mite_decode(mite_LKCR_strings, value);
- offset = MITE_LKAR(channel);
- value = readl(mite_io_addr + offset);
- pr_debug("mite status[LKAR] at 0x%08x =0x%08x\n", offset, value);
- offset = MITE_CHSR(channel);
- value = readl(mite_io_addr + offset);
- pr_debug("mite status[CHSR] at 0x%08x =0x%08x\n", offset, value);
- mite_decode(mite_CHSR_strings, value);
- offset = MITE_FCR(channel);
- value = readl(mite_io_addr + offset);
- pr_debug("mite status[FCR] at 0x%08x =0x%08x\n", offset, value);
-}
-EXPORT_SYMBOL_GPL(mite_dump_regs);
-#endif
-
static int __init mite_module_init(void)
{
return 0;
diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h
index 8423b8bf338..e6e58e989b7 100644
--- a/drivers/staging/comedi/drivers/mite.h
+++ b/drivers/staging/comedi/drivers/mite.h
@@ -24,21 +24,14 @@
#include <linux/slab.h>
#include "../comedidev.h"
-/* #define DEBUG_MITE */
#define PCIMIO_COMPAT
-#ifdef DEBUG_MITE
-#define MDPRINTK(format, args...) pr_debug(format , ## args)
-#else
-#define MDPRINTK(format, args...) do { } while (0)
-#endif
-
#define MAX_MITE_DMA_CHANNELS 8
struct mite_dma_descriptor {
- u32 count;
- u32 addr;
- u32 next;
+ __le32 count;
+ __le32 addr;
+ __le32 next;
u32 dar;
};
@@ -113,9 +106,9 @@ unsigned mite_dma_tcr(struct mite_channel *mite_chan);
void mite_dma_arm(struct mite_channel *mite_chan);
void mite_dma_disarm(struct mite_channel *mite_chan);
int mite_sync_input_dma(struct mite_channel *mite_chan,
- struct comedi_async *async);
+ struct comedi_subdevice *s);
int mite_sync_output_dma(struct mite_channel *mite_chan,
- struct comedi_async *async);
+ struct comedi_subdevice *s);
u32 mite_bytes_written_to_memory_lb(struct mite_channel *mite_chan);
u32 mite_bytes_written_to_memory_ub(struct mite_channel *mite_chan);
u32 mite_bytes_read_from_memory_lb(struct mite_channel *mite_chan);
@@ -127,12 +120,7 @@ int mite_done(struct mite_channel *mite_chan);
void mite_prep_dma(struct mite_channel *mite_chan,
unsigned int num_device_bits, unsigned int num_memory_bits);
int mite_buf_change(struct mite_dma_descriptor_ring *ring,
- struct comedi_async *async);
-
-#ifdef DEBUG_MITE
-void mite_print_chsr(unsigned int chsr);
-void mite_dump_regs(struct mite_channel *mite_chan);
-#endif
+ struct comedi_subdevice *s);
static inline int CHAN_OFFSET(int channel)
{
diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c
index acbaeee6250..f770400a0e8 100644
--- a/drivers/staging/comedi/drivers/mpc624.c
+++ b/drivers/staging/comedi/drivers/mpc624.c
@@ -142,8 +142,18 @@ static const struct comedi_lrange range_mpc624_bipolar10 = {
}
};
-/* Timeout 200ms */
-#define TIMEOUT 200
+static int mpc624_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned char status;
+
+ status = inb(dev->iobase + MPC624_ADC);
+ if ((status & MPC624_ADBUSY) == 0)
+ return 0;
+ return -EBUSY;
+}
static int mpc624_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
@@ -152,18 +162,13 @@ static int mpc624_ai_rinsn(struct comedi_device *dev,
struct mpc624_private *devpriv = dev->private;
int n, i;
unsigned long int data_in, data_out;
- unsigned char ucPort;
+ int ret;
/*
* WARNING:
* We always write 0 to GNSWA bit, so the channel range is +-/10.1Vdc
*/
outb(insn->chanspec, dev->iobase + MPC624_GNMUXCH);
-/* printk("Channel %d:\n", insn->chanspec); */
- if (!insn->n) {
- printk(KERN_INFO "MPC624: Warning, no data to acquire\n");
- return 0;
- }
for (n = 0; n < insn->n; n++) {
/* Trigger the conversion */
@@ -175,18 +180,10 @@ static int mpc624_ai_rinsn(struct comedi_device *dev,
udelay(1);
/* Wait for the conversion to end */
- for (i = 0; i < TIMEOUT; i++) {
- ucPort = inb(dev->iobase + MPC624_ADC);
- if (ucPort & MPC624_ADBUSY)
- udelay(1000);
- else
- break;
- }
- if (i == TIMEOUT) {
- printk(KERN_ERR "MPC624: timeout (%dms)\n", TIMEOUT);
- data[n] = 0;
- return -ETIMEDOUT;
- }
+ ret = comedi_timeout(dev, s, insn, mpc624_ai_eoc, 0);
+ if (ret)
+ return ret;
+
/* Start reading data */
data_in = 0;
data_out = devpriv->ulConvertionRate;
@@ -245,11 +242,11 @@ static int mpc624_ai_rinsn(struct comedi_device *dev,
*/
if (data_in & MPC624_EOC_BIT)
- printk(KERN_INFO "MPC624:EOC bit is set (data_in=%lu)!",
- data_in);
+ dev_dbg(dev->class_dev,
+ "EOC bit is set (data_in=%lu)!", data_in);
if (data_in & MPC624_DMY_BIT)
- printk(KERN_INFO "MPC624:DMY bit is set (data_in=%lu)!",
- data_in);
+ dev_dbg(dev->class_dev,
+ "DMY bit is set (data_in=%lu)!", data_in);
if (data_in & MPC624_SGN_BIT) { /* Volatge is positive */
/*
* comedi operates on unsigned numbers, so mask off EOC
@@ -348,7 +345,7 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->len_chanlist = 1;
s->insn_read = mpc624_ai_rinsn;
- return 1;
+ return 0;
}
static struct comedi_driver mpc624_driver = {
diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c
index 3ca755eca28..b74b9e9bfd4 100644
--- a/drivers/staging/comedi/drivers/multiq3.c
+++ b/drivers/staging/comedi/drivers/multiq3.c
@@ -81,34 +81,44 @@ struct multiq3_private {
unsigned int ao_readback[2];
};
+static int multiq3_ai_status(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + MULTIQ3_STATUS);
+ if (status & context)
+ return 0;
+ return -EBUSY;
+}
+
static int multiq3_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- int i, n;
+ int n;
int chan;
unsigned int hi, lo;
+ int ret;
chan = CR_CHAN(insn->chanspec);
outw(MULTIQ3_CONTROL_MUST | MULTIQ3_AD_MUX_EN | (chan << 3),
dev->iobase + MULTIQ3_CONTROL);
- for (i = 0; i < MULTIQ3_TIMEOUT; i++) {
- if (inw(dev->iobase + MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC)
- break;
- }
- if (i == MULTIQ3_TIMEOUT)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, multiq3_ai_status,
+ MULTIQ3_STATUS_EOC);
+ if (ret)
+ return ret;
for (n = 0; n < insn->n; n++) {
outw(0, dev->iobase + MULTIQ3_AD_CS);
- for (i = 0; i < MULTIQ3_TIMEOUT; i++) {
- if (inw(dev->iobase +
- MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC_I)
- break;
- }
- if (i == MULTIQ3_TIMEOUT)
- return -ETIMEDOUT;
+
+ ret = comedi_timeout(dev, s, insn, multiq3_ai_status,
+ MULTIQ3_STATUS_EOC_I);
+ if (ret)
+ return ret;
hi = inb(dev->iobase + MULTIQ3_AD_CS);
lo = inb(dev->iobase + MULTIQ3_AD_CS);
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index 85aa9609d6a..c8b1fa793a3 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -215,7 +215,7 @@ static irqreturn_t ni6527_interrupt(int irq, void *d)
return IRQ_NONE;
if (status & NI6527_STATUS_EDGE) {
- comedi_buf_put(s->async, 0);
+ comedi_buf_put(s, 0);
s->async->events |= COMEDI_CB_EOS;
comedi_event(dev, s);
}
@@ -253,7 +253,7 @@ static int ni6527_intr_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
- err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
if (err)
@@ -421,6 +421,7 @@ static int ni6527_auto_attach(struct comedi_device *dev,
s->range_table = &range_digital;
s->insn_config = ni6527_intr_insn_config;
s->insn_bits = ni6527_intr_insn_bits;
+ s->len_chanlist = 1;
s->do_cmdtest = ni6527_intr_cmdtest;
s->do_cmd = ni6527_intr_cmd;
s->cancel = ni6527_intr_cancel;
@@ -455,7 +456,7 @@ static int ni6527_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &ni6527_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(ni6527_pci_table) = {
+static const struct pci_device_id ni6527_pci_table[] = {
{ PCI_VDEVICE(NI, 0x2b10), BOARD_PXI6527 },
{ PCI_VDEVICE(NI, 0x2b20), BOARD_PCI6527 },
{ 0 }
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index 853f62b2b1a..9a139d6b8ef 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -43,9 +43,6 @@ except maybe the 6514.
*/
-#define DEBUG 1
-#define DEBUG_FLAGS
-
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
@@ -430,7 +427,7 @@ static irqreturn_t ni_65xx_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct ni_65xx_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[2];
+ struct comedi_subdevice *s = dev->read_subdev;
unsigned int status;
status = readb(devpriv->mite->daq_io_addr + Change_Status);
@@ -442,7 +439,7 @@ static irqreturn_t ni_65xx_interrupt(int irq, void *d)
writeb(ClrEdge | ClrOverflow,
devpriv->mite->daq_io_addr + Clear_Register);
- comedi_buf_put(s->async, 0);
+ comedi_buf_put(s, 0);
s->async->events |= COMEDI_CB_EOS;
comedi_event(dev, s);
return IRQ_HANDLED;
@@ -476,7 +473,7 @@ static int ni_65xx_intr_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
- err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
if (err)
@@ -494,7 +491,6 @@ static int ni_65xx_intr_cmd(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct ni_65xx_private *devpriv = dev->private;
- /* struct comedi_cmd *cmd = &s->async->cmd; */
writeb(ClrEdge | ClrOverflow,
devpriv->mite->daq_io_addr + Clear_Register);
@@ -674,6 +670,7 @@ static int ni_65xx_auto_attach(struct comedi_device *dev,
s->n_chan = 1;
s->range_table = &range_unknown;
s->maxdata = 1;
+ s->len_chanlist = 1;
s->do_cmdtest = ni_65xx_intr_cmdtest;
s->do_cmd = ni_65xx_intr_cmd;
s->cancel = ni_65xx_intr_cancel;
@@ -741,7 +738,7 @@ static int ni_65xx_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &ni_65xx_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(ni_65xx_pci_table) = {
+static const struct pci_device_id ni_65xx_pci_table[] = {
{ PCI_VDEVICE(NI, 0x1710), BOARD_PXI6509 },
{ PCI_VDEVICE(NI, 0x7085), BOARD_PCI6509 },
{ PCI_VDEVICE(NI, 0x7086), BOARD_PXI6528 },
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index 8a991dcab24..634cde83a02 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -40,6 +40,7 @@
#include "../comedidev.h"
+#include "comedi_fc.h"
#include "mite.h"
#include "ni_tio.h"
@@ -55,112 +56,112 @@ for 4 */
#define MAX_DMA_CHANNEL 4
/* See Register-Level Programmer Manual page 3.1 */
-enum NI_660x_Register {
- G0InterruptAcknowledge,
- G0StatusRegister,
- G1InterruptAcknowledge,
- G1StatusRegister,
- G01StatusRegister,
- G0CommandRegister,
- STCDIOParallelInput,
- G1CommandRegister,
- G0HWSaveRegister,
- G1HWSaveRegister,
- STCDIOOutput,
- STCDIOControl,
- G0SWSaveRegister,
- G1SWSaveRegister,
- G0ModeRegister,
- G01JointStatus1Register,
- G1ModeRegister,
- STCDIOSerialInput,
- G0LoadARegister,
- G01JointStatus2Register,
- G0LoadBRegister,
- G1LoadARegister,
- G1LoadBRegister,
- G0InputSelectRegister,
- G1InputSelectRegister,
- G0AutoincrementRegister,
- G1AutoincrementRegister,
- G01JointResetRegister,
- G0InterruptEnable,
- G1InterruptEnable,
- G0CountingModeRegister,
- G1CountingModeRegister,
- G0SecondGateRegister,
- G1SecondGateRegister,
- G0DMAConfigRegister,
- G0DMAStatusRegister,
- G1DMAConfigRegister,
- G1DMAStatusRegister,
- G2InterruptAcknowledge,
- G2StatusRegister,
- G3InterruptAcknowledge,
- G3StatusRegister,
- G23StatusRegister,
- G2CommandRegister,
- G3CommandRegister,
- G2HWSaveRegister,
- G3HWSaveRegister,
- G2SWSaveRegister,
- G3SWSaveRegister,
- G2ModeRegister,
- G23JointStatus1Register,
- G3ModeRegister,
- G2LoadARegister,
- G23JointStatus2Register,
- G2LoadBRegister,
- G3LoadARegister,
- G3LoadBRegister,
- G2InputSelectRegister,
- G3InputSelectRegister,
- G2AutoincrementRegister,
- G3AutoincrementRegister,
- G23JointResetRegister,
- G2InterruptEnable,
- G3InterruptEnable,
- G2CountingModeRegister,
- G3CountingModeRegister,
- G3SecondGateRegister,
- G2SecondGateRegister,
- G2DMAConfigRegister,
- G2DMAStatusRegister,
- G3DMAConfigRegister,
- G3DMAStatusRegister,
- DIO32Input,
- DIO32Output,
- ClockConfigRegister,
- GlobalInterruptStatusRegister,
- DMAConfigRegister,
- GlobalInterruptConfigRegister,
- IOConfigReg0_1,
- IOConfigReg2_3,
- IOConfigReg4_5,
- IOConfigReg6_7,
- IOConfigReg8_9,
- IOConfigReg10_11,
- IOConfigReg12_13,
- IOConfigReg14_15,
- IOConfigReg16_17,
- IOConfigReg18_19,
- IOConfigReg20_21,
- IOConfigReg22_23,
- IOConfigReg24_25,
- IOConfigReg26_27,
- IOConfigReg28_29,
- IOConfigReg30_31,
- IOConfigReg32_33,
- IOConfigReg34_35,
- IOConfigReg36_37,
- IOConfigReg38_39,
- NumRegisters,
+enum ni_660x_register {
+ NI660X_G0_INT_ACK,
+ NI660X_G0_STATUS,
+ NI660X_G1_INT_ACK,
+ NI660X_G1_STATUS,
+ NI660X_G01_STATUS,
+ NI660X_G0_CMD,
+ NI660X_STC_DIO_PARALLEL_INPUT,
+ NI660X_G1_CMD,
+ NI660X_G0_HW_SAVE,
+ NI660X_G1_HW_SAVE,
+ NI660X_STC_DIO_OUTPUT,
+ NI660X_STC_DIO_CONTROL,
+ NI660X_G0_SW_SAVE,
+ NI660X_G1_SW_SAVE,
+ NI660X_G0_MODE,
+ NI660X_G01_STATUS1,
+ NI660X_G1_MODE,
+ NI660X_STC_DIO_SERIAL_INPUT,
+ NI660X_G0_LOADA,
+ NI660X_G01_STATUS2,
+ NI660X_G0_LOADB,
+ NI660X_G1_LOADA,
+ NI660X_G1_LOADB,
+ NI660X_G0_INPUT_SEL,
+ NI660X_G1_INPUT_SEL,
+ NI660X_G0_AUTO_INC,
+ NI660X_G1_AUTO_INC,
+ NI660X_G01_RESET,
+ NI660X_G0_INT_ENA,
+ NI660X_G1_INT_ENA,
+ NI660X_G0_CNT_MODE,
+ NI660X_G1_CNT_MODE,
+ NI660X_G0_GATE2,
+ NI660X_G1_GATE2,
+ NI660X_G0_DMA_CFG,
+ NI660X_G0_DMA_STATUS,
+ NI660X_G1_DMA_CFG,
+ NI660X_G1_DMA_STATUS,
+ NI660X_G2_INT_ACK,
+ NI660X_G2_STATUS,
+ NI660X_G3_INT_ACK,
+ NI660X_G3_STATUS,
+ NI660X_G23_STATUS,
+ NI660X_G2_CMD,
+ NI660X_G3_CMD,
+ NI660X_G2_HW_SAVE,
+ NI660X_G3_HW_SAVE,
+ NI660X_G2_SW_SAVE,
+ NI660X_G3_SW_SAVE,
+ NI660X_G2_MODE,
+ NI660X_G23_STATUS1,
+ NI660X_G3_MODE,
+ NI660X_G2_LOADA,
+ NI660X_G23_STATUS2,
+ NI660X_G2_LOADB,
+ NI660X_G3_LOADA,
+ NI660X_G3_LOADB,
+ NI660X_G2_INPUT_SEL,
+ NI660X_G3_INPUT_SEL,
+ NI660X_G2_AUTO_INC,
+ NI660X_G3_AUTO_INC,
+ NI660X_G23_RESET,
+ NI660X_G2_INT_ENA,
+ NI660X_G3_INT_ENA,
+ NI660X_G2_CNT_MODE,
+ NI660X_G3_CNT_MODE,
+ NI660X_G3_GATE2,
+ NI660X_G2_GATE2,
+ NI660X_G2_DMA_CFG,
+ NI660X_G2_DMA_STATUS,
+ NI660X_G3_DMA_CFG,
+ NI660X_G3_DMA_STATUS,
+ NI660X_DIO32_INPUT,
+ NI660X_DIO32_OUTPUT,
+ NI660X_CLK_CFG,
+ NI660X_GLOBAL_INT_STATUS,
+ NI660X_DMA_CFG,
+ NI660X_GLOBAL_INT_CFG,
+ NI660X_IO_CFG_0_1,
+ NI660X_IO_CFG_2_3,
+ NI660X_IO_CFG_4_5,
+ NI660X_IO_CFG_6_7,
+ NI660X_IO_CFG_8_9,
+ NI660X_IO_CFG_10_11,
+ NI660X_IO_CFG_12_13,
+ NI660X_IO_CFG_14_15,
+ NI660X_IO_CFG_16_17,
+ NI660X_IO_CFG_18_19,
+ NI660X_IO_CFG_20_21,
+ NI660X_IO_CFG_22_23,
+ NI660X_IO_CFG_24_25,
+ NI660X_IO_CFG_26_27,
+ NI660X_IO_CFG_28_29,
+ NI660X_IO_CFG_30_31,
+ NI660X_IO_CFG_32_33,
+ NI660X_IO_CFG_34_35,
+ NI660X_IO_CFG_36_37,
+ NI660X_IO_CFG_38_39,
+ NI660X_NUM_REGS,
};
static inline unsigned IOConfigReg(unsigned pfi_channel)
{
- unsigned reg = IOConfigReg0_1 + pfi_channel / 2;
- BUG_ON(reg > IOConfigReg38_39);
+ unsigned reg = NI660X_IO_CFG_0_1 + pfi_channel / 2;
+ BUG_ON(reg > NI660X_IO_CFG_38_39);
return reg;
}
@@ -200,7 +201,7 @@ struct NI_660xRegisterData {
enum ni_660x_register_width size; /* 1 byte, 2 bytes, or 4 bytes */
};
-static const struct NI_660xRegisterData registerData[NumRegisters] = {
+static const struct NI_660xRegisterData registerData[NI660X_NUM_REGS] = {
{"G0 Interrupt Acknowledge", 0x004, NI_660x_WRITE, DATA_2B},
{"G0 Status Register", 0x004, NI_660x_READ, DATA_2B},
{"G1 Interrupt Acknowledge", 0x006, NI_660x_WRITE, DATA_2B},
@@ -347,11 +348,6 @@ static inline unsigned dma_select_mask(unsigned dma_channel)
enum dma_selection {
dma_selection_none = 0x1f,
};
-static inline unsigned dma_selection_counter(unsigned counter_index)
-{
- BUG_ON(counter_index >= counters_per_chip);
- return counter_index;
-}
static inline unsigned dma_select_bits(unsigned dma_channel, unsigned selection)
{
@@ -444,229 +440,158 @@ static inline unsigned ni_660x_num_counters(struct comedi_device *dev)
return board->n_chips * counters_per_chip;
}
-static enum NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg)
+static enum ni_660x_register ni_gpct_to_660x_register(enum ni_gpct_register reg)
{
- enum NI_660x_Register ni_660x_register;
switch (reg) {
- case NITIO_G0_Autoincrement_Reg:
- ni_660x_register = G0AutoincrementRegister;
- break;
- case NITIO_G1_Autoincrement_Reg:
- ni_660x_register = G1AutoincrementRegister;
- break;
- case NITIO_G2_Autoincrement_Reg:
- ni_660x_register = G2AutoincrementRegister;
- break;
- case NITIO_G3_Autoincrement_Reg:
- ni_660x_register = G3AutoincrementRegister;
- break;
- case NITIO_G0_Command_Reg:
- ni_660x_register = G0CommandRegister;
- break;
- case NITIO_G1_Command_Reg:
- ni_660x_register = G1CommandRegister;
- break;
- case NITIO_G2_Command_Reg:
- ni_660x_register = G2CommandRegister;
- break;
- case NITIO_G3_Command_Reg:
- ni_660x_register = G3CommandRegister;
- break;
- case NITIO_G0_HW_Save_Reg:
- ni_660x_register = G0HWSaveRegister;
- break;
- case NITIO_G1_HW_Save_Reg:
- ni_660x_register = G1HWSaveRegister;
- break;
- case NITIO_G2_HW_Save_Reg:
- ni_660x_register = G2HWSaveRegister;
- break;
- case NITIO_G3_HW_Save_Reg:
- ni_660x_register = G3HWSaveRegister;
- break;
- case NITIO_G0_SW_Save_Reg:
- ni_660x_register = G0SWSaveRegister;
- break;
- case NITIO_G1_SW_Save_Reg:
- ni_660x_register = G1SWSaveRegister;
- break;
- case NITIO_G2_SW_Save_Reg:
- ni_660x_register = G2SWSaveRegister;
- break;
- case NITIO_G3_SW_Save_Reg:
- ni_660x_register = G3SWSaveRegister;
- break;
- case NITIO_G0_Mode_Reg:
- ni_660x_register = G0ModeRegister;
- break;
- case NITIO_G1_Mode_Reg:
- ni_660x_register = G1ModeRegister;
- break;
- case NITIO_G2_Mode_Reg:
- ni_660x_register = G2ModeRegister;
- break;
- case NITIO_G3_Mode_Reg:
- ni_660x_register = G3ModeRegister;
- break;
- case NITIO_G0_LoadA_Reg:
- ni_660x_register = G0LoadARegister;
- break;
- case NITIO_G1_LoadA_Reg:
- ni_660x_register = G1LoadARegister;
- break;
- case NITIO_G2_LoadA_Reg:
- ni_660x_register = G2LoadARegister;
- break;
- case NITIO_G3_LoadA_Reg:
- ni_660x_register = G3LoadARegister;
- break;
- case NITIO_G0_LoadB_Reg:
- ni_660x_register = G0LoadBRegister;
- break;
- case NITIO_G1_LoadB_Reg:
- ni_660x_register = G1LoadBRegister;
- break;
- case NITIO_G2_LoadB_Reg:
- ni_660x_register = G2LoadBRegister;
- break;
- case NITIO_G3_LoadB_Reg:
- ni_660x_register = G3LoadBRegister;
- break;
- case NITIO_G0_Input_Select_Reg:
- ni_660x_register = G0InputSelectRegister;
- break;
- case NITIO_G1_Input_Select_Reg:
- ni_660x_register = G1InputSelectRegister;
- break;
- case NITIO_G2_Input_Select_Reg:
- ni_660x_register = G2InputSelectRegister;
- break;
- case NITIO_G3_Input_Select_Reg:
- ni_660x_register = G3InputSelectRegister;
- break;
- case NITIO_G01_Status_Reg:
- ni_660x_register = G01StatusRegister;
- break;
- case NITIO_G23_Status_Reg:
- ni_660x_register = G23StatusRegister;
- break;
- case NITIO_G01_Joint_Reset_Reg:
- ni_660x_register = G01JointResetRegister;
- break;
- case NITIO_G23_Joint_Reset_Reg:
- ni_660x_register = G23JointResetRegister;
- break;
- case NITIO_G01_Joint_Status1_Reg:
- ni_660x_register = G01JointStatus1Register;
- break;
- case NITIO_G23_Joint_Status1_Reg:
- ni_660x_register = G23JointStatus1Register;
- break;
- case NITIO_G01_Joint_Status2_Reg:
- ni_660x_register = G01JointStatus2Register;
- break;
- case NITIO_G23_Joint_Status2_Reg:
- ni_660x_register = G23JointStatus2Register;
- break;
- case NITIO_G0_Counting_Mode_Reg:
- ni_660x_register = G0CountingModeRegister;
- break;
- case NITIO_G1_Counting_Mode_Reg:
- ni_660x_register = G1CountingModeRegister;
- break;
- case NITIO_G2_Counting_Mode_Reg:
- ni_660x_register = G2CountingModeRegister;
- break;
- case NITIO_G3_Counting_Mode_Reg:
- ni_660x_register = G3CountingModeRegister;
- break;
- case NITIO_G0_Second_Gate_Reg:
- ni_660x_register = G0SecondGateRegister;
- break;
- case NITIO_G1_Second_Gate_Reg:
- ni_660x_register = G1SecondGateRegister;
- break;
- case NITIO_G2_Second_Gate_Reg:
- ni_660x_register = G2SecondGateRegister;
- break;
- case NITIO_G3_Second_Gate_Reg:
- ni_660x_register = G3SecondGateRegister;
- break;
- case NITIO_G0_DMA_Config_Reg:
- ni_660x_register = G0DMAConfigRegister;
- break;
- case NITIO_G0_DMA_Status_Reg:
- ni_660x_register = G0DMAStatusRegister;
- break;
- case NITIO_G1_DMA_Config_Reg:
- ni_660x_register = G1DMAConfigRegister;
- break;
- case NITIO_G1_DMA_Status_Reg:
- ni_660x_register = G1DMAStatusRegister;
- break;
- case NITIO_G2_DMA_Config_Reg:
- ni_660x_register = G2DMAConfigRegister;
- break;
- case NITIO_G2_DMA_Status_Reg:
- ni_660x_register = G2DMAStatusRegister;
- break;
- case NITIO_G3_DMA_Config_Reg:
- ni_660x_register = G3DMAConfigRegister;
- break;
- case NITIO_G3_DMA_Status_Reg:
- ni_660x_register = G3DMAStatusRegister;
- break;
- case NITIO_G0_Interrupt_Acknowledge_Reg:
- ni_660x_register = G0InterruptAcknowledge;
- break;
- case NITIO_G1_Interrupt_Acknowledge_Reg:
- ni_660x_register = G1InterruptAcknowledge;
- break;
- case NITIO_G2_Interrupt_Acknowledge_Reg:
- ni_660x_register = G2InterruptAcknowledge;
- break;
- case NITIO_G3_Interrupt_Acknowledge_Reg:
- ni_660x_register = G3InterruptAcknowledge;
- break;
- case NITIO_G0_Status_Reg:
- ni_660x_register = G0StatusRegister;
- break;
- case NITIO_G1_Status_Reg:
- ni_660x_register = G1StatusRegister;
- break;
- case NITIO_G2_Status_Reg:
- ni_660x_register = G2StatusRegister;
- break;
- case NITIO_G3_Status_Reg:
- ni_660x_register = G3StatusRegister;
- break;
- case NITIO_G0_Interrupt_Enable_Reg:
- ni_660x_register = G0InterruptEnable;
- break;
- case NITIO_G1_Interrupt_Enable_Reg:
- ni_660x_register = G1InterruptEnable;
- break;
- case NITIO_G2_Interrupt_Enable_Reg:
- ni_660x_register = G2InterruptEnable;
- break;
- case NITIO_G3_Interrupt_Enable_Reg:
- ni_660x_register = G3InterruptEnable;
- break;
+ case NITIO_G0_AUTO_INC:
+ return NI660X_G0_AUTO_INC;
+ case NITIO_G1_AUTO_INC:
+ return NI660X_G1_AUTO_INC;
+ case NITIO_G2_AUTO_INC:
+ return NI660X_G2_AUTO_INC;
+ case NITIO_G3_AUTO_INC:
+ return NI660X_G3_AUTO_INC;
+ case NITIO_G0_CMD:
+ return NI660X_G0_CMD;
+ case NITIO_G1_CMD:
+ return NI660X_G1_CMD;
+ case NITIO_G2_CMD:
+ return NI660X_G2_CMD;
+ case NITIO_G3_CMD:
+ return NI660X_G3_CMD;
+ case NITIO_G0_HW_SAVE:
+ return NI660X_G0_HW_SAVE;
+ case NITIO_G1_HW_SAVE:
+ return NI660X_G1_HW_SAVE;
+ case NITIO_G2_HW_SAVE:
+ return NI660X_G2_HW_SAVE;
+ case NITIO_G3_HW_SAVE:
+ return NI660X_G3_HW_SAVE;
+ case NITIO_G0_SW_SAVE:
+ return NI660X_G0_SW_SAVE;
+ case NITIO_G1_SW_SAVE:
+ return NI660X_G1_SW_SAVE;
+ case NITIO_G2_SW_SAVE:
+ return NI660X_G2_SW_SAVE;
+ case NITIO_G3_SW_SAVE:
+ return NI660X_G3_SW_SAVE;
+ case NITIO_G0_MODE:
+ return NI660X_G0_MODE;
+ case NITIO_G1_MODE:
+ return NI660X_G1_MODE;
+ case NITIO_G2_MODE:
+ return NI660X_G2_MODE;
+ case NITIO_G3_MODE:
+ return NI660X_G3_MODE;
+ case NITIO_G0_LOADA:
+ return NI660X_G0_LOADA;
+ case NITIO_G1_LOADA:
+ return NI660X_G1_LOADA;
+ case NITIO_G2_LOADA:
+ return NI660X_G2_LOADA;
+ case NITIO_G3_LOADA:
+ return NI660X_G3_LOADA;
+ case NITIO_G0_LOADB:
+ return NI660X_G0_LOADB;
+ case NITIO_G1_LOADB:
+ return NI660X_G1_LOADB;
+ case NITIO_G2_LOADB:
+ return NI660X_G2_LOADB;
+ case NITIO_G3_LOADB:
+ return NI660X_G3_LOADB;
+ case NITIO_G0_INPUT_SEL:
+ return NI660X_G0_INPUT_SEL;
+ case NITIO_G1_INPUT_SEL:
+ return NI660X_G1_INPUT_SEL;
+ case NITIO_G2_INPUT_SEL:
+ return NI660X_G2_INPUT_SEL;
+ case NITIO_G3_INPUT_SEL:
+ return NI660X_G3_INPUT_SEL;
+ case NITIO_G01_STATUS:
+ return NI660X_G01_STATUS;
+ case NITIO_G23_STATUS:
+ return NI660X_G23_STATUS;
+ case NITIO_G01_RESET:
+ return NI660X_G01_RESET;
+ case NITIO_G23_RESET:
+ return NI660X_G23_RESET;
+ case NITIO_G01_STATUS1:
+ return NI660X_G01_STATUS1;
+ case NITIO_G23_STATUS1:
+ return NI660X_G23_STATUS1;
+ case NITIO_G01_STATUS2:
+ return NI660X_G01_STATUS2;
+ case NITIO_G23_STATUS2:
+ return NI660X_G23_STATUS2;
+ case NITIO_G0_CNT_MODE:
+ return NI660X_G0_CNT_MODE;
+ case NITIO_G1_CNT_MODE:
+ return NI660X_G1_CNT_MODE;
+ case NITIO_G2_CNT_MODE:
+ return NI660X_G2_CNT_MODE;
+ case NITIO_G3_CNT_MODE:
+ return NI660X_G3_CNT_MODE;
+ case NITIO_G0_GATE2:
+ return NI660X_G0_GATE2;
+ case NITIO_G1_GATE2:
+ return NI660X_G1_GATE2;
+ case NITIO_G2_GATE2:
+ return NI660X_G2_GATE2;
+ case NITIO_G3_GATE2:
+ return NI660X_G3_GATE2;
+ case NITIO_G0_DMA_CFG:
+ return NI660X_G0_DMA_CFG;
+ case NITIO_G0_DMA_STATUS:
+ return NI660X_G0_DMA_STATUS;
+ case NITIO_G1_DMA_CFG:
+ return NI660X_G1_DMA_CFG;
+ case NITIO_G1_DMA_STATUS:
+ return NI660X_G1_DMA_STATUS;
+ case NITIO_G2_DMA_CFG:
+ return NI660X_G2_DMA_CFG;
+ case NITIO_G2_DMA_STATUS:
+ return NI660X_G2_DMA_STATUS;
+ case NITIO_G3_DMA_CFG:
+ return NI660X_G3_DMA_CFG;
+ case NITIO_G3_DMA_STATUS:
+ return NI660X_G3_DMA_STATUS;
+ case NITIO_G0_INT_ACK:
+ return NI660X_G0_INT_ACK;
+ case NITIO_G1_INT_ACK:
+ return NI660X_G1_INT_ACK;
+ case NITIO_G2_INT_ACK:
+ return NI660X_G2_INT_ACK;
+ case NITIO_G3_INT_ACK:
+ return NI660X_G3_INT_ACK;
+ case NITIO_G0_STATUS:
+ return NI660X_G0_STATUS;
+ case NITIO_G1_STATUS:
+ return NI660X_G1_STATUS;
+ case NITIO_G2_STATUS:
+ return NI660X_G2_STATUS;
+ case NITIO_G3_STATUS:
+ return NI660X_G3_STATUS;
+ case NITIO_G0_INT_ENA:
+ return NI660X_G0_INT_ENA;
+ case NITIO_G1_INT_ENA:
+ return NI660X_G1_INT_ENA;
+ case NITIO_G2_INT_ENA:
+ return NI660X_G2_INT_ENA;
+ case NITIO_G3_INT_ENA:
+ return NI660X_G3_INT_ENA;
default:
BUG();
return 0;
- break;
}
- return ni_660x_register;
}
static inline void ni_660x_write_register(struct comedi_device *dev,
- unsigned chip_index, unsigned bits,
- enum NI_660x_Register reg)
+ unsigned chip, unsigned bits,
+ enum ni_660x_register reg)
{
struct ni_660x_private *devpriv = dev->private;
void __iomem *write_address =
- devpriv->mite->daq_io_addr + GPCT_OFFSET[chip_index] +
+ devpriv->mite->daq_io_addr + GPCT_OFFSET[chip] +
registerData[reg].offset;
switch (registerData[reg].size) {
@@ -683,12 +608,12 @@ static inline void ni_660x_write_register(struct comedi_device *dev,
}
static inline unsigned ni_660x_read_register(struct comedi_device *dev,
- unsigned chip_index,
- enum NI_660x_Register reg)
+ unsigned chip,
+ enum ni_660x_register reg)
{
struct ni_660x_private *devpriv = dev->private;
void __iomem *read_address =
- devpriv->mite->daq_io_addr + GPCT_OFFSET[chip_index] +
+ devpriv->mite->daq_io_addr + GPCT_OFFSET[chip] +
registerData[reg].offset;
switch (registerData[reg].size) {
@@ -709,18 +634,20 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits,
enum ni_gpct_register reg)
{
struct comedi_device *dev = counter->counter_dev->dev;
- enum NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg);
- ni_660x_write_register(dev, counter->chip_index, bits,
- ni_660x_register);
+ enum ni_660x_register ni_660x_register = ni_gpct_to_660x_register(reg);
+ unsigned chip = counter->chip_index;
+
+ ni_660x_write_register(dev, chip, bits, ni_660x_register);
}
static unsigned ni_gpct_read_register(struct ni_gpct *counter,
enum ni_gpct_register reg)
{
struct comedi_device *dev = counter->counter_dev->dev;
- enum NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg);
- return ni_660x_read_register(dev, counter->chip_index,
- ni_660x_register);
+ enum ni_660x_register ni_660x_register = ni_gpct_to_660x_register(reg);
+ unsigned chip = counter->chip_index;
+
+ return ni_660x_read_register(dev, chip, ni_660x_register);
}
static inline struct mite_dma_descriptor_ring *mite_ring(struct ni_660x_private
@@ -728,7 +655,9 @@ static inline struct mite_dma_descriptor_ring *mite_ring(struct ni_660x_private
struct ni_gpct
*counter)
{
- return priv->mite_rings[counter->chip_index][counter->counter_index];
+ unsigned chip = counter->chip_index;
+
+ return priv->mite_rings[chip][counter->counter_index];
}
static inline void ni_660x_set_dma_channel(struct comedi_device *dev,
@@ -736,18 +665,17 @@ static inline void ni_660x_set_dma_channel(struct comedi_device *dev,
struct ni_gpct *counter)
{
struct ni_660x_private *devpriv = dev->private;
+ unsigned chip = counter->chip_index;
unsigned long flags;
spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
- devpriv->dma_configuration_soft_copies[counter->chip_index] &=
- ~dma_select_mask(mite_channel);
- devpriv->dma_configuration_soft_copies[counter->chip_index] |=
- dma_select_bits(mite_channel,
- dma_selection_counter(counter->counter_index));
- ni_660x_write_register(dev, counter->chip_index,
- devpriv->dma_configuration_soft_copies
- [counter->chip_index] |
- dma_reset_bit(mite_channel), DMAConfigRegister);
+ devpriv->dma_configuration_soft_copies[chip] &=
+ ~dma_select_mask(mite_channel);
+ devpriv->dma_configuration_soft_copies[chip] |=
+ dma_select_bits(mite_channel, counter->counter_index);
+ ni_660x_write_register(dev, chip,
+ devpriv->dma_configuration_soft_copies[chip] |
+ dma_reset_bit(mite_channel), NI660X_DMA_CFG);
mmiowb();
spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
}
@@ -757,16 +685,17 @@ static inline void ni_660x_unset_dma_channel(struct comedi_device *dev,
struct ni_gpct *counter)
{
struct ni_660x_private *devpriv = dev->private;
+ unsigned chip = counter->chip_index;
unsigned long flags;
spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags);
- devpriv->dma_configuration_soft_copies[counter->chip_index] &=
+ devpriv->dma_configuration_soft_copies[chip] &=
~dma_select_mask(mite_channel);
- devpriv->dma_configuration_soft_copies[counter->chip_index] |=
+ devpriv->dma_configuration_soft_copies[chip] |=
dma_select_bits(mite_channel, dma_selection_none);
- ni_660x_write_register(dev, counter->chip_index,
- devpriv->dma_configuration_soft_copies
- [counter->chip_index], DMAConfigRegister);
+ ni_660x_write_register(dev, chip,
+ devpriv->dma_configuration_soft_copies[chip],
+ NI660X_DMA_CFG);
mmiowb();
spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags);
}
@@ -815,11 +744,9 @@ static void ni_660x_release_mite_channel(struct comedi_device *dev,
static int ni_660x_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ struct ni_gpct *counter = s->private;
int retval;
- struct ni_gpct *counter = subdev_to_counter(s);
-/* const struct comedi_cmd *cmd = &s->async->cmd; */
-
retval = ni_660x_request_mite_channel(dev, counter, COMEDI_INPUT);
if (retval) {
comedi_error(dev,
@@ -827,22 +754,13 @@ static int ni_660x_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
return retval;
}
ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL, NULL);
- retval = ni_tio_cmd(counter, s->async);
-
- return retval;
-}
-
-static int ni_660x_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd)
-{
- struct ni_gpct *counter = subdev_to_counter(s);
- return ni_tio_cmdtest(counter, cmd);
+ return ni_tio_cmd(dev, s);
}
static int ni_660x_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
- struct ni_gpct *counter = subdev_to_counter(s);
+ struct ni_gpct *counter = s->private;
int retval;
retval = ni_tio_cancel(counter);
@@ -850,30 +768,29 @@ static int ni_660x_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
return retval;
}
-static void set_tio_counterswap(struct comedi_device *dev, int chipset)
+static void set_tio_counterswap(struct comedi_device *dev, int chip)
{
- /* See P. 3.5 of the Register-Level Programming manual. The
- CounterSwap bit has to be set on the second chip, otherwise
- it will try to use the same pins as the first chip.
+ unsigned bits = 0;
+
+ /*
+ * See P. 3.5 of the Register-Level Programming manual.
+ * The CounterSwap bit has to be set on the second chip,
+ * otherwise it will try to use the same pins as the
+ * first chip.
*/
- if (chipset)
- ni_660x_write_register(dev, chipset, CounterSwap,
- ClockConfigRegister);
- else
- ni_660x_write_register(dev, chipset, 0, ClockConfigRegister);
+ if (chip)
+ bits = CounterSwap;
+
+ ni_660x_write_register(dev, chip, bits, NI660X_CLK_CFG);
}
static void ni_660x_handle_gpct_interrupt(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- ni_tio_handle_interrupt(subdev_to_counter(s), s);
- if (s->async->events) {
- if (s->async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
- COMEDI_CB_OVERFLOW)) {
- ni_660x_cancel(dev, s);
- }
- comedi_event(dev, s);
- }
+ struct ni_gpct *counter = s->private;
+
+ ni_tio_handle_interrupt(counter, s);
+ cfc_handle_events(dev, s);
}
static irqreturn_t ni_660x_interrupt(int irq, void *d)
@@ -901,13 +818,14 @@ static int ni_660x_input_poll(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct ni_660x_private *devpriv = dev->private;
+ struct ni_gpct *counter = s->private;
unsigned long flags;
/* lock to avoid race with comedi_poll */
spin_lock_irqsave(&devpriv->interrupt_lock, flags);
- mite_sync_input_dma(subdev_to_counter(s)->mite_chan, s->async);
+ mite_sync_input_dma(counter->mite_chan, s);
spin_unlock_irqrestore(&devpriv->interrupt_lock, flags);
- return comedi_buf_read_n_available(s->async);
+ return comedi_buf_read_n_available(s);
}
static int ni_660x_buf_change(struct comedi_device *dev,
@@ -915,10 +833,10 @@ static int ni_660x_buf_change(struct comedi_device *dev,
unsigned long new_size)
{
struct ni_660x_private *devpriv = dev->private;
+ struct ni_gpct *counter = s->private;
int ret;
- ret = mite_buf_change(mite_ring(devpriv, subdev_to_counter(s)),
- s->async);
+ ret = mite_buf_change(mite_ring(devpriv, counter), s);
if (ret < 0)
return ret;
@@ -974,13 +892,6 @@ static void ni_660x_free_mite_rings(struct comedi_device *dev)
}
}
-static int
-ni_660x_GPCT_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- return ni_tio_rinsn(subdev_to_counter(s), insn, data);
-}
-
static void init_tio_chip(struct comedi_device *dev, int chipset)
{
struct ni_660x_private *devpriv = dev->private;
@@ -994,25 +905,11 @@ static void init_tio_chip(struct comedi_device *dev, int chipset)
}
ni_660x_write_register(dev, chipset,
devpriv->dma_configuration_soft_copies[chipset],
- DMAConfigRegister);
+ NI660X_DMA_CFG);
for (i = 0; i < NUM_PFI_CHANNELS; ++i)
ni_660x_write_register(dev, chipset, 0, IOConfigReg(i));
}
-static int
-ni_660x_GPCT_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- return ni_tio_insn_config(subdev_to_counter(s), insn, data);
-}
-
-static int ni_660x_GPCT_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- return ni_tio_winsn(subdev_to_counter(s), insn, data);
-}
-
static int ni_660x_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -1024,13 +921,13 @@ static int ni_660x_dio_insn_bits(struct comedi_device *dev,
s->state &= ~(data[0] << base_bitfield_channel);
s->state |= (data[0] & data[1]) << base_bitfield_channel;
/* Write out the new digital output lines */
- ni_660x_write_register(dev, 0, s->state, DIO32Output);
+ ni_660x_write_register(dev, 0, s->state, NI660X_DIO32_OUTPUT);
}
/* on return, data[1] contains the value of the digital
* input and output lines. */
- data[1] =
- (ni_660x_read_register(dev, 0,
- DIO32Input) >> base_bitfield_channel);
+ data[1] = (ni_660x_read_register(dev, 0, NI660X_DIO32_INPUT) >>
+ base_bitfield_channel);
+
return insn->n;
}
@@ -1215,7 +1112,7 @@ static int ni_660x_auto_attach(struct comedi_device *dev,
s->insn_config = ni_660x_dio_insn_config;
/* we use the ioconfig registers to control dio direction, so zero
output enables in stc dio control reg */
- ni_660x_write_register(dev, 0, 0, STCDIOControl);
+ ni_660x_write_register(dev, 0, 0, NI660X_STC_DIO_CONTROL);
devpriv->counter_dev = ni_gpct_device_construct(dev,
&ni_gpct_write_register,
@@ -1234,12 +1131,12 @@ static int ni_660x_auto_attach(struct comedi_device *dev,
SDF_CMD_READ /* | SDF_CMD_WRITE */ ;
s->n_chan = 3;
s->maxdata = 0xffffffff;
- s->insn_read = ni_660x_GPCT_rinsn;
- s->insn_write = ni_660x_GPCT_winsn;
- s->insn_config = ni_660x_GPCT_insn_config;
+ s->insn_read = ni_tio_insn_read;
+ s->insn_write = ni_tio_insn_write;
+ s->insn_config = ni_tio_insn_config;
s->do_cmd = &ni_660x_cmd;
s->len_chanlist = 1;
- s->do_cmdtest = &ni_660x_cmdtest;
+ s->do_cmdtest = ni_tio_cmdtest;
s->cancel = &ni_660x_cancel;
s->poll = &ni_660x_input_poll;
s->async_dma_dir = DMA_BIDIRECTIONAL;
@@ -1284,8 +1181,8 @@ static int ni_660x_auto_attach(struct comedi_device *dev,
if (board->n_chips > 1)
global_interrupt_config_bits |= Cascade_Int_Enable_Bit;
ni_660x_write_register(dev, 0, global_interrupt_config_bits,
- GlobalInterruptConfigRegister);
- dev_info(dev->class_dev, "ni_660x: %s attached\n", dev->board_name);
+ NI660X_GLOBAL_INT_CFG);
+
return 0;
}
@@ -1320,7 +1217,7 @@ static int ni_660x_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &ni_660x_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(ni_660x_pci_table) = {
+static const struct pci_device_id ni_660x_pci_table[] = {
{ PCI_VDEVICE(NI, 0x1310), BOARD_PCI6602 },
{ PCI_VDEVICE(NI, 0x1360), BOARD_PXI6602 },
{ PCI_VDEVICE(NI, 0x2c60), BOARD_PCI6601 },
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index e4414cf110e..1002ceacfdc 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -246,9 +246,6 @@ static int ni_670x_auto_attach(struct comedi_device *dev,
/* Config of ao registers */
writel(0x00, devpriv->mite->daq_io_addr + AO_CONTROL_OFFSET);
- dev_info(dev->class_dev, "%s: %s attached\n",
- dev->driver->driver_name, dev->board_name);
-
return 0;
}
@@ -282,7 +279,7 @@ static int ni_670x_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &ni_670x_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(ni_670x_pci_table) = {
+static const struct pci_device_id ni_670x_pci_table[] = {
{ PCI_VDEVICE(NI, 0x1290), BOARD_PCI6704 },
{ PCI_VDEVICE(NI, 0x1920), BOARD_PXI6704 },
{ PCI_VDEVICE(NI, 0x2c90), BOARD_PCI6703 },
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index 63c847932eb..5bd19494dbf 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -74,9 +74,6 @@ TRIG_WAKE_EOS
#define A2150_SIZE 28
#define A2150_DMA_BUFFER_SIZE 0xff00 /* size in bytes of dma buffer */
-/* #define A2150_DEBUG enable debugging code */
-#undef A2150_DEBUG /* disable debugging code */
-
/* Registers and bits */
#define CONFIG_REG 0x0
#define CHANNEL_BITS(x) ((x) & 0x7)
@@ -127,10 +124,9 @@ struct a2150_board {
/* analog input range */
static const struct comedi_lrange range_a2150 = {
- 1,
- {
- RANGE(-2.828, 2.828),
- }
+ 1, {
+ BIP_RANGE(2.828)
+ }
};
/* enum must match board indices */
@@ -167,19 +163,6 @@ static int a2150_get_timing(struct comedi_device *dev, unsigned int *period,
static int a2150_set_chanlist(struct comedi_device *dev,
unsigned int start_channel,
unsigned int num_channels);
-#ifdef A2150_DEBUG
-
-static void ni_dump_regs(struct comedi_device *dev)
-{
- struct a2150_private *devpriv = dev->private;
-
- printk("config bits 0x%x\n", devpriv->config_bits);
- printk("irq dma bits 0x%x\n", devpriv->irq_dma_bits);
- printk("status bits 0x%x\n", inw(dev->iobase + STATUS_REG));
-}
-
-#endif
-
/* interrupt service routine */
static irqreturn_t a2150_interrupt(int irq, void *d)
{
@@ -201,7 +184,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
}
/* initialize async here to make sure s is not NULL */
async = s->async;
- async->events = 0;
cmd = &async->cmd;
status = inw(dev->iobase + STATUS_REG);
@@ -213,15 +195,14 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
if (status & OVFL_BIT) {
comedi_error(dev, "fifo overflow");
- a2150_cancel(dev, s);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ cfc_handle_events(dev, s);
}
if ((status & DMA_TC_BIT) == 0) {
comedi_error(dev, "caught non-dma interrupt? Aborting.");
- a2150_cancel(dev, s);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
@@ -266,7 +247,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
cfc_write_to_buffer(s, dpnt);
if (cmd->stop_src == TRIG_COUNT) {
if (--devpriv->count == 0) { /* end of acquisition */
- a2150_cancel(dev, s);
async->events |= COMEDI_CB_EOA;
break;
}
@@ -282,7 +262,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
async->events |= COMEDI_CB_BLOCK;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
/* clear interrupt */
outw(0x00, dev->iobase + DMA_TC_CLEAR_REG);
@@ -307,14 +287,54 @@ static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
+static int a2150_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
+ unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
+ int i;
+
+ if (cmd->chanlist_len == 2 && (chan0 == 1 || chan0 == 3)) {
+ dev_dbg(dev->class_dev,
+ "length 2 chanlist must be channels 0,1 or channels 2,3\n");
+ return -EINVAL;
+ }
+
+ if (cmd->chanlist_len == 3) {
+ dev_dbg(dev->class_dev,
+ "chanlist must have 1,2 or 4 channels\n");
+ return -EINVAL;
+ }
+
+ for (i = 1; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+ unsigned int aref = CR_AREF(cmd->chanlist[i]);
+
+ if (chan != (chan0 + i)) {
+ dev_dbg(dev->class_dev,
+ "entries in chanlist must be consecutive channels, counting upwards\n");
+ return -EINVAL;
+ }
+
+ if (chan == 2)
+ aref0 = aref;
+ if (aref != aref0) {
+ dev_dbg(dev->class_dev,
+ "channels 0/1 and 2/3 must have the same analog reference\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int a2150_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
const struct a2150_board *thisboard = comedi_board(dev);
int err = 0;
- int tmp;
- int startChan;
- int i;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -359,42 +379,17 @@ static int a2150_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
- a2150_get_timing(dev, &cmd->scan_begin_arg, cmd->flags);
- if (tmp != cmd->scan_begin_arg)
- err++;
+ arg = cmd->scan_begin_arg;
+ a2150_get_timing(dev, &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
if (err)
return 4;
- /* check channel/gain list against card's limitations */
- if (cmd->chanlist) {
- startChan = CR_CHAN(cmd->chanlist[0]);
- for (i = 1; i < cmd->chanlist_len; i++) {
- if (CR_CHAN(cmd->chanlist[i]) != (startChan + i)) {
- comedi_error(dev,
- "entries in chanlist must be consecutive channels, counting upwards\n");
- err++;
- }
- }
- if (cmd->chanlist_len == 2 && CR_CHAN(cmd->chanlist[0]) == 1) {
- comedi_error(dev,
- "length 2 chanlist must be channels 0,1 or channels 2,3");
- err++;
- }
- if (cmd->chanlist_len == 3) {
- comedi_error(dev,
- "chanlist must have 1,2 or 4 channels");
- err++;
- }
- if (CR_AREF(cmd->chanlist[0]) != CR_AREF(cmd->chanlist[1]) ||
- CR_AREF(cmd->chanlist[2]) != CR_AREF(cmd->chanlist[3])) {
- comedi_error(dev,
- "channels 0/1 and 2/3 must have the same analog reference");
- err++;
- }
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= a2150_ai_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -407,15 +402,11 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
struct a2150_private *devpriv = dev->private;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
+ unsigned long timer_base = dev->iobase + I8253_BASE_REG;
unsigned long lock_flags;
unsigned int old_config_bits = devpriv->config_bits;
unsigned int trigger_bits;
- if (!dev->irq || !devpriv->dma) {
- comedi_error(dev,
- " irq and dma required, cannot do hardware conversions");
- return -1;
- }
if (cmd->flags & TRIG_RT) {
comedi_error(dev,
" dma incompatible with hard real-time interrupt (TRIG_RT), aborting");
@@ -479,7 +470,8 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG);
/* may need to wait 72 sampling periods if timing was changed */
- i8254_load(dev->iobase + I8253_BASE_REG, 0, 2, 72, 0);
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY);
+ i8254_write(timer_base, 0, 2, 72);
/* setup start triggering */
trigger_bits = 0;
@@ -506,20 +498,29 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* start acquisition for soft trigger */
if (cmd->start_src == TRIG_NOW)
outw(0, dev->iobase + FIFO_START_REG);
-#ifdef A2150_DEBUG
- ni_dump_regs(dev);
-#endif
return 0;
}
+static int a2150_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + STATUS_REG);
+ if (status & FNE_BIT)
+ return 0;
+ return -EBUSY;
+}
+
static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct a2150_private *devpriv = dev->private;
- unsigned int i, n;
- static const int timeout = 100000;
- static const int filter_delay = 36;
+ unsigned int n;
+ int ret;
/* clear fifo and reset triggering circuitry */
outw(0, dev->iobase + FIFO_RESET_REG);
@@ -549,37 +550,21 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
* there is a 35.6 sample delay for data to get through the
* antialias filter
*/
- for (n = 0; n < filter_delay; n++) {
- for (i = 0; i < timeout; i++) {
- if (inw(dev->iobase + STATUS_REG) & FNE_BIT)
- break;
- udelay(1);
- }
- if (i == timeout) {
- comedi_error(dev, "timeout");
- return -ETIME;
- }
+ for (n = 0; n < 36; n++) {
+ ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0);
+ if (ret)
+ return ret;
+
inw(dev->iobase + FIFO_DATA_REG);
}
/* read data */
for (n = 0; n < insn->n; n++) {
- for (i = 0; i < timeout; i++) {
- if (inw(dev->iobase + STATUS_REG) & FNE_BIT)
- break;
- udelay(1);
- }
- if (i == timeout) {
- comedi_error(dev, "timeout");
- return -ETIME;
- }
-#ifdef A2150_DEBUG
- ni_dump_regs(dev);
-#endif
+ ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0);
+ if (ret)
+ return ret;
+
data[n] = inw(dev->iobase + FIFO_DATA_REG);
-#ifdef A2150_DEBUG
- printk(" data is %i\n", data[n]);
-#endif
data[n] ^= 0x8000;
}
@@ -711,7 +696,7 @@ static int a2150_probe(struct comedi_device *dev)
static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct a2150_board *thisboard = comedi_board(dev);
+ const struct a2150_board *thisboard;
struct a2150_private *devpriv;
struct comedi_subdevice *s;
unsigned int irq = it->options[1];
@@ -728,46 +713,35 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- /* grab our IRQ */
- if (irq) {
- /* check that irq is supported */
- if (irq < 3 || irq == 8 || irq == 13 || irq > 15) {
- printk(" invalid irq line %u\n", irq);
- return -EINVAL;
- }
- if (request_irq(irq, a2150_interrupt, 0,
- dev->driver->driver_name, dev)) {
- printk("unable to allocate irq %u\n", irq);
- return -EINVAL;
+ dev->board_ptr = a2150_boards + a2150_probe(dev);
+ thisboard = comedi_board(dev);
+ dev->board_name = thisboard->name;
+
+ if ((irq >= 3 && irq <= 7) || (irq >= 9 && irq <= 12) ||
+ irq == 14 || irq == 15) {
+ ret = request_irq(irq, a2150_interrupt, 0,
+ dev->board_name, dev);
+ if (ret == 0) {
+ devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq);
+ dev->irq = irq;
}
- devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq);
- dev->irq = irq;
}
- /* initialize dma */
- if (dma) {
- if (dma == 4 || dma > 7) {
- printk(" invalid dma channel %u\n", dma);
- return -EINVAL;
- }
- if (request_dma(dma, dev->driver->driver_name)) {
- printk(" failed to allocate dma channel %u\n", dma);
- return -EINVAL;
- }
- devpriv->dma = dma;
- devpriv->dma_buffer =
- kmalloc(A2150_DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
- if (devpriv->dma_buffer == NULL)
- return -ENOMEM;
- disable_dma(dma);
- set_dma_mode(dma, DMA_MODE_READ);
+ if (dev->irq && dma <= 7 && dma != 4) {
+ ret = request_dma(dma, dev->board_name);
+ if (ret == 0) {
+ devpriv->dma = dma;
+ devpriv->dma_buffer = kmalloc(A2150_DMA_BUFFER_SIZE,
+ GFP_KERNEL | GFP_DMA);
+ if (!devpriv->dma_buffer)
+ return -ENOMEM;
- devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma);
- }
+ disable_dma(dma);
+ set_dma_mode(dma, DMA_MODE_READ);
- dev->board_ptr = a2150_boards + a2150_probe(dev);
- thisboard = comedi_board(dev);
- dev->board_name = thisboard->name;
+ devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma);
+ }
+ }
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
@@ -775,17 +749,20 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* analog input subdevice */
s = &dev->subdevices[0];
- dev->read_subdev = s;
s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER;
s->n_chan = 4;
- s->len_chanlist = 4;
s->maxdata = 0xffff;
s->range_table = &range_a2150;
- s->do_cmd = a2150_ai_cmd;
- s->do_cmdtest = a2150_ai_cmdtest;
s->insn_read = a2150_ai_rinsn;
- s->cancel = a2150_cancel;
+ if (dev->irq && devpriv->dma) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = s->n_chan;
+ s->do_cmd = a2150_ai_cmd;
+ s->do_cmdtest = a2150_ai_cmdtest;
+ s->cancel = a2150_cancel;
+ }
/* need to do this for software counting of completed conversions, to
* prevent hardware count from stopping acquisition */
diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index 10e3e9475ee..c93b47bcca5 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -310,6 +310,7 @@ static int atao_calib_insn_read(struct comedi_device *dev,
static void atao_reset(struct comedi_device *dev)
{
struct atao_private *devpriv = dev->private;
+ unsigned long timer_base = dev->iobase + ATAO_82C53_BASE;
/* This is the reset sequence described in the manual */
@@ -317,10 +318,9 @@ static void atao_reset(struct comedi_device *dev)
outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG);
/* Put outputs of counter 1 and counter 2 in a high state */
- i8254_load(dev->iobase + ATAO_82C53_BASE, 0,
- 0, 0x0003, I8254_MODE4 | I8254_BINARY);
- i8254_set_mode(dev->iobase + ATAO_82C53_BASE, 0,
- 1, I8254_MODE4 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 0, I8254_MODE4 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE4 | I8254_BINARY);
+ i8254_write(timer_base, 0, 0, 0x0003);
outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG);
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index 856c73d8b7c..d03935257b9 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -98,8 +98,6 @@ are not supported.
#include "ni_stc.h"
#include "8255.h"
-#undef DEBUG
-
#define ATMIO 1
#undef PCIMIO
@@ -437,19 +435,6 @@ static int ni_atmio_attach(struct comedi_device *dev,
if (ret)
return ret;
-#ifdef DEBUG
- /* board existence sanity check */
- {
- int i;
-
- printk(" board fingerprint:");
- for (i = 0; i < 16; i += 2) {
- printk(" %04x %02x", inw(dev->iobase + i),
- inb(dev->iobase + i + 1));
- }
- }
-#endif
-
/* get board type */
board = ni_getboardtype(dev);
diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index a9f7d40d6db..6ad27f50c6e 100644
--- a/drivers/staging/comedi/drivers/ni_atmio16d.c
+++ b/drivers/staging/comedi/drivers/ni_atmio16d.c
@@ -96,7 +96,6 @@ Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d)
#define CLOCK_100_HZ 0x8F25
/* Other miscellaneous defines */
#define ATMIO16D_SIZE 32 /* bus address range */
-#define ATMIO16D_TIMEOUT 10
struct atmio16_board_t {
@@ -105,40 +104,31 @@ struct atmio16_board_t {
};
/* range structs */
-static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { 4, {
- BIP_RANGE
- (10),
- BIP_RANGE
- (1),
- BIP_RANGE
- (0.1),
- BIP_RANGE
- (0.02)
- }
+static const struct comedi_lrange range_atmio16d_ai_10_bipolar = {
+ 4, {
+ BIP_RANGE(10),
+ BIP_RANGE(1),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.02)
+ }
};
-static const struct comedi_lrange range_atmio16d_ai_5_bipolar = { 4, {
- BIP_RANGE
- (5),
- BIP_RANGE
- (0.5),
- BIP_RANGE
- (0.05),
- BIP_RANGE
- (0.01)
- }
+static const struct comedi_lrange range_atmio16d_ai_5_bipolar = {
+ 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.05),
+ BIP_RANGE(0.01)
+ }
};
-static const struct comedi_lrange range_atmio16d_ai_unipolar = { 4, {
- UNI_RANGE
- (10),
- UNI_RANGE
- (1),
- UNI_RANGE
- (0.1),
- UNI_RANGE
- (0.02)
- }
+static const struct comedi_lrange range_atmio16d_ai_unipolar = {
+ 4, {
+ UNI_RANGE(10),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1),
+ UNI_RANGE(0.02)
+ }
};
/* private data struct */
@@ -229,9 +219,9 @@ static void reset_atmio16d(struct comedi_device *dev)
static irqreturn_t atmio16d_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
- struct comedi_subdevice *s = &dev->subdevices[0];
+ struct comedi_subdevice *s = dev->read_subdev;
- comedi_buf_put(s->async, inw(dev->iobase + AD_FIFO_REG));
+ comedi_buf_put(s, inw(dev->iobase + AD_FIFO_REG));
comedi_event(dev, s);
return IRQ_HANDLED;
@@ -457,16 +447,32 @@ static int atmio16d_ai_cancel(struct comedi_device *dev,
return 0;
}
-/* Mode 0 is used to get a single conversion on demand */
+static int atmio16d_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + STAT_REG);
+ if (status & STAT_AD_CONVAVAIL)
+ return 0;
+ if (status & STAT_AD_OVERFLOW) {
+ outw(0, dev->iobase + AD_CLEAR_REG);
+ return -EOVERFLOW;
+ }
+ return -EBUSY;
+}
+
static int atmio16d_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct atmio16d_private *devpriv = dev->private;
- int i, t;
+ int i;
int chan;
int gain;
- int status;
+ int ret;
chan = CR_CHAN(insn->chanspec);
gain = CR_RANGE(insn->chanspec);
@@ -482,31 +488,17 @@ static int atmio16d_ai_insn_read(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
/* start the conversion */
outw(0, dev->iobase + START_CONVERT_REG);
+
/* wait for it to finish */
- for (t = 0; t < ATMIO16D_TIMEOUT; t++) {
- /* check conversion status */
- status = inw(dev->iobase + STAT_REG);
- if (status & STAT_AD_CONVAVAIL) {
- /* read the data now */
- data[i] = inw(dev->iobase + AD_FIFO_REG);
- /* change to two's complement if need be */
- if (devpriv->adc_coding == adc_2comp)
- data[i] ^= 0x800;
- break;
- }
- if (status & STAT_AD_OVERFLOW) {
- printk(KERN_INFO "atmio16d: a/d FIFO overflow\n");
- outw(0, dev->iobase + AD_CLEAR_REG);
-
- return -ETIME;
- }
- }
- /* end waiting, now check if it timed out */
- if (t == ATMIO16D_TIMEOUT) {
- printk(KERN_INFO "atmio16d: timeout\n");
+ ret = comedi_timeout(dev, s, insn, atmio16d_ai_eoc, 0);
+ if (ret)
+ return ret;
- return -ETIME;
- }
+ /* read the data now */
+ data[i] = inw(dev->iobase + AD_FIFO_REG);
+ /* change to two's complement if need be */
+ if (devpriv->adc_coding == adc_2comp)
+ data[i] ^= 0x800;
}
return i;
@@ -636,7 +628,6 @@ static int atmio16d_attach(struct comedi_device *dev,
const struct atmio16_board_t *board = comedi_board(dev);
struct atmio16d_private *devpriv;
struct comedi_subdevice *s;
- unsigned int irq;
int ret;
ret = comedi_request_region(dev, it->options[0], ATMIO16D_SIZE);
@@ -654,19 +645,11 @@ static int atmio16d_attach(struct comedi_device *dev,
/* reset the atmio16d hardware */
reset_atmio16d(dev);
- /* check if our interrupt is available and get it */
- irq = it->options[1];
- if (irq) {
-
- ret = request_irq(irq, atmio16d_interrupt, 0, "atmio16d", dev);
- if (ret < 0) {
- printk(KERN_INFO "failed to allocate irq %u\n", irq);
- return ret;
- }
- dev->irq = irq;
- printk(KERN_INFO "( irq = %u )\n", irq);
- } else {
- printk(KERN_INFO "( no irq )");
+ if (it->options[1]) {
+ ret = request_irq(it->options[1], atmio16d_interrupt, 0,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = it->options[1];
}
/* set device options */
@@ -682,16 +665,11 @@ static int atmio16d_attach(struct comedi_device *dev,
/* setup sub-devices */
s = &dev->subdevices[0];
- dev->read_subdev = s;
/* ai subdevice */
s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND;
s->n_chan = (devpriv->adc_mux ? 16 : 8);
- s->len_chanlist = 16;
s->insn_read = atmio16d_ai_insn_read;
- s->do_cmdtest = atmio16d_ai_cmdtest;
- s->do_cmd = atmio16d_ai_cmd;
- s->cancel = atmio16d_ai_cancel;
s->maxdata = 0xfff; /* 4095 decimal */
switch (devpriv->adc_range) {
case adc_bipolar10:
@@ -704,6 +682,14 @@ static int atmio16d_attach(struct comedi_device *dev,
s->range_table = &range_atmio16d_ai_unipolar;
break;
}
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = 16;
+ s->do_cmdtest = atmio16d_ai_cmdtest;
+ s->do_cmd = atmio16d_ai_cmd;
+ s->cancel = atmio16d_ai_cancel;
+ }
/* ao subdevice */
s = &dev->subdevices[1];
@@ -743,10 +729,13 @@ static int atmio16d_attach(struct comedi_device *dev,
/* 8255 subdevice */
s = &dev->subdevices[3];
- if (board->has_8255)
- subdev_8255_init(dev, s, NULL, dev->iobase);
- else
+ if (board->has_8255) {
+ ret = subdev_8255_init(dev, s, NULL, dev->iobase);
+ if (ret)
+ return ret;
+ } else {
s->type = COMEDI_SUBD_UNUSED;
+ }
/* don't yet know how to deal with counter/timers */
#if 0
@@ -756,7 +745,6 @@ static int atmio16d_attach(struct comedi_device *dev,
s->n_chan = 0;
s->maxdata = 0
#endif
- printk("\n");
return 0;
}
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index e4cdca34915..728bf7f14f7 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -109,19 +109,38 @@ static int daq700_dio_insn_config(struct comedi_device *dev,
return insn->n;
}
+static int daq700_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + STA_R2);
+ if ((status & 0x03))
+ return -EOVERFLOW;
+ status = inb(dev->iobase + STA_R1);
+ if ((status & 0x02))
+ return -ENODATA;
+ if ((status & 0x11) == 0x01)
+ return 0;
+ return -EBUSY;
+}
+
static int daq700_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- int n, i, chan;
+ int n, chan;
int d;
- unsigned int status;
- enum { TIMEOUT = 100 };
+ int ret;
chan = CR_CHAN(insn->chanspec);
/* write channel to multiplexer */
/* set mask scan bit high to disable scanning */
outb(chan | 0x80, dev->iobase + CMD_R1);
+ /* mux needs 2us to really settle [Fred Brooks]. */
+ udelay(2);
/* convert n samples */
for (n = 0; n < insn->n; n++) {
@@ -130,30 +149,12 @@ static int daq700_ai_rinsn(struct comedi_device *dev,
outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */
/* mode 1 out0 H, L to H, start conversion */
outb(0x32, dev->iobase + CMO_R);
+
/* wait for conversion to end */
- for (i = 0; i < TIMEOUT; i++) {
- status = inb(dev->iobase + STA_R2);
- if ((status & 0x03) != 0) {
- dev_info(dev->class_dev,
- "Overflow/run Error\n");
- return -EOVERFLOW;
- }
- status = inb(dev->iobase + STA_R1);
- if ((status & 0x02) != 0) {
- dev_info(dev->class_dev, "Data Error\n");
- return -ENODATA;
- }
- if ((status & 0x11) == 0x01) {
- /* ADC conversion complete */
- break;
- }
- udelay(1);
- }
- if (i == TIMEOUT) {
- dev_info(dev->class_dev,
- "timeout during ADC conversion\n");
- return -ETIMEDOUT;
- }
+ ret = comedi_timeout(dev, s, insn, daq700_ai_eoc, 0);
+ if (ret)
+ return ret;
+
/* read data */
d = inw(dev->iobase + ADFIFO_R);
/* mangle the data as necessary */
@@ -229,11 +230,6 @@ static int daq700_auto_attach(struct comedi_device *dev,
s->insn_read = daq700_ai_rinsn;
daq700_ai_config(dev, s);
- dev_info(dev->class_dev, "%s: %s, io 0x%lx\n",
- dev->driver->driver_name,
- dev->board_name,
- dev->iobase);
-
return 0;
}
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index 335ea34fa57..925e82c65b2 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -3,8 +3,8 @@
Driver for National Instruments PCMCIA DAQ-Card DIO-24
Copyright (C) 2002 Daniel Vecino Castel <dvecino@able.es>
- PCMCIA crap at end of file is adapted from dummy_cs.c 1.31 2001/08/24 12:13:13
- from the pcmcia package.
+ PCMCIA crap at end of file is adapted from dummy_cs.c 1.31
+ 2001/08/24 12:13:13 from the pcmcia package.
The initial developer of the pcmcia dummy_cs.c code is David A. Hinds
<dahinds@users.sourceforge.net>. Portions created by David A. Hinds
are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 0512445df08..3e3f940fa57 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -73,7 +73,6 @@
#include "ni_labpc_isadma.h"
#define LABPC_SIZE 0x20 /* size of ISA io region */
-#define LABPC_ADC_TIMEOUT 1000
enum scan_mode {
MODE_SINGLE_CHAN,
@@ -172,32 +171,39 @@ static const struct labpc_boardinfo labpc_boards[] = {
};
#endif
-static int labpc_counter_load(struct comedi_device *dev,
- unsigned long base_address,
- unsigned int counter_number,
- unsigned int count, unsigned int mode)
+static void labpc_counter_load(struct comedi_device *dev,
+ unsigned long base_address,
+ unsigned int counter_number,
+ unsigned int count,
+ unsigned int mode)
{
const struct labpc_boardinfo *board = comedi_board(dev);
- if (board->has_mmio)
- return i8254_mm_load((void __iomem *)base_address, 0,
- counter_number, count, mode);
- else
- return i8254_load(base_address, 0, counter_number, count, mode);
+ if (board->has_mmio) {
+ void __iomem *mmio_base = (void __iomem *)base_address;
+
+ i8254_mm_set_mode(mmio_base, 0, counter_number, mode);
+ i8254_mm_write(mmio_base, 0, counter_number, count);
+ } else {
+ i8254_set_mode(base_address, 0, counter_number, mode);
+ i8254_write(base_address, 0, counter_number, count);
+ }
}
-static int labpc_counter_set_mode(struct comedi_device *dev,
- unsigned long base_address,
- unsigned int counter_number,
- unsigned int mode)
+static void labpc_counter_set_mode(struct comedi_device *dev,
+ unsigned long base_address,
+ unsigned int counter_number,
+ unsigned int mode)
{
const struct labpc_boardinfo *board = comedi_board(dev);
- if (board->has_mmio)
- return i8254_mm_set_mode((void __iomem *)base_address, 0,
- counter_number, mode);
- else
- return i8254_set_mode(base_address, 0, counter_number, mode);
+ if (board->has_mmio) {
+ void __iomem *mmio_base = (void __iomem *)base_address;
+
+ i8254_mm_set_mode(mmio_base, 0, counter_number, mode);
+ } else {
+ i8254_set_mode(base_address, 0, counter_number, mode);
+ }
}
static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
@@ -308,19 +314,17 @@ static void labpc_clear_adc_fifo(struct comedi_device *dev)
labpc_read_adc_fifo(dev);
}
-static int labpc_ai_wait_for_data(struct comedi_device *dev,
- int timeout)
+static int labpc_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
struct labpc_private *devpriv = dev->private;
- int i;
- for (i = 0; i < timeout; i++) {
- devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
- if (devpriv->stat1 & STAT1_DAVAIL)
- return 0;
- udelay(1);
- }
- return -ETIME;
+ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
+ if (devpriv->stat1 & STAT1_DAVAIL)
+ return 0;
+ return -EBUSY;
}
static int labpc_ai_insn_read(struct comedi_device *dev,
@@ -352,10 +356,8 @@ static int labpc_ai_insn_read(struct comedi_device *dev,
devpriv->write_byte(devpriv->cmd4, dev->iobase + CMD4_REG);
/* initialize pacer counter to prevent any problems */
- ret = labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG,
- 0, I8254_MODE2);
- if (ret)
- return ret;
+ labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG,
+ 0, I8254_MODE2);
labpc_clear_adc_fifo(dev);
@@ -363,7 +365,7 @@ static int labpc_ai_insn_read(struct comedi_device *dev,
/* trigger conversion */
devpriv->write_byte(0x1, dev->iobase + ADC_START_CONVERT_REG);
- ret = labpc_ai_wait_for_data(dev, LABPC_ADC_TIMEOUT);
+ ret = comedi_timeout(dev, s, insn, labpc_ai_eoc, 0);
if (ret)
return ret;
@@ -549,72 +551,60 @@ static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd)
return 0;
}
-static int labpc_ai_chanlist_invalid(const struct comedi_device *dev,
- const struct comedi_cmd *cmd,
- enum scan_mode mode)
+static int labpc_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
{
- int channel, range, aref, i;
-
- if (cmd->chanlist == NULL)
- return 0;
+ enum scan_mode mode = labpc_ai_scan_mode(cmd);
+ unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
+ unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
+ unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
+ int i;
if (mode == MODE_SINGLE_CHAN)
return 0;
- if (mode == MODE_SINGLE_CHAN_INTERVAL) {
- if (cmd->chanlist_len > 0xff) {
- comedi_error(dev,
- "ni_labpc: chanlist too long for single channel interval mode\n");
- return 1;
- }
- }
-
- channel = CR_CHAN(cmd->chanlist[0]);
- range = CR_RANGE(cmd->chanlist[0]);
- aref = CR_AREF(cmd->chanlist[0]);
-
for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+ unsigned int range = CR_RANGE(cmd->chanlist[i]);
+ unsigned int aref = CR_AREF(cmd->chanlist[i]);
switch (mode) {
+ case MODE_SINGLE_CHAN:
+ break;
case MODE_SINGLE_CHAN_INTERVAL:
- if (CR_CHAN(cmd->chanlist[i]) != channel) {
- comedi_error(dev,
- "channel scanning order specified in chanlist is not supported by hardware.\n");
- return 1;
+ if (chan != chan0) {
+ dev_dbg(dev->class_dev,
+ "channel scanning order specified in chanlist is not supported by hardware\n");
+ return -EINVAL;
}
break;
case MODE_MULT_CHAN_UP:
- if (CR_CHAN(cmd->chanlist[i]) != i) {
- comedi_error(dev,
- "channel scanning order specified in chanlist is not supported by hardware.\n");
- return 1;
+ if (chan != i) {
+ dev_dbg(dev->class_dev,
+ "channel scanning order specified in chanlist is not supported by hardware\n");
+ return -EINVAL;
}
break;
case MODE_MULT_CHAN_DOWN:
- if (CR_CHAN(cmd->chanlist[i]) !=
- cmd->chanlist_len - i - 1) {
- comedi_error(dev,
- "channel scanning order specified in chanlist is not supported by hardware.\n");
- return 1;
+ if (chan != (cmd->chanlist_len - i - 1)) {
+ dev_dbg(dev->class_dev,
+ "channel scanning order specified in chanlist is not supported by hardware\n");
+ return -EINVAL;
}
break;
- default:
- dev_err(dev->class_dev,
- "ni_labpc: bug! in chanlist check\n");
- return 1;
- break;
}
- if (CR_RANGE(cmd->chanlist[i]) != range) {
- comedi_error(dev,
- "entries in chanlist must all have the same range\n");
- return 1;
+ if (range != range0) {
+ dev_dbg(dev->class_dev,
+ "entries in chanlist must all have the same range\n");
+ return -EINVAL;
}
- if (CR_AREF(cmd->chanlist[i]) != aref) {
- comedi_error(dev,
- "entries in chanlist must all have the same reference\n");
- return 1;
+ if (aref != aref0) {
+ dev_dbg(dev->class_dev,
+ "entries in chanlist must all have the same reference\n");
+ return -EINVAL;
}
}
@@ -664,8 +654,14 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
/* Step 3: check if arguments are trivially valid */
- if (cmd->start_arg == TRIG_NOW)
+ switch (cmd->start_src) {
+ case TRIG_NOW:
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ break;
+ case TRIG_EXT:
+ /* start_arg value is ignored */
+ break;
+ }
if (!cmd->chanlist_len)
err |= -EINVAL;
@@ -714,7 +710,11 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
if (err)
return 4;
- if (labpc_ai_chanlist_invalid(dev, cmd, mode))
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= labpc_ai_check_chanlist(dev, s, cmd);
+
+ if (err)
return 5;
return 0;
@@ -735,7 +735,6 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
unsigned int aref = CR_AREF(chanspec);
enum transfer_type xfer;
unsigned long flags;
- int ret;
/* make sure board is disabled before setting up acquisition */
labpc_cancel(dev, s);
@@ -750,17 +749,12 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* load counter a1 with count of 3
* (pc+ manual says this is minimum allowed) using mode 0
*/
- ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG,
- 1, 3, I8254_MODE0);
+ labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG,
+ 1, 3, I8254_MODE0);
} else {
/* just put counter a1 in mode 0 to set its output low */
- ret = labpc_counter_set_mode(dev,
- dev->iobase + COUNTER_A_BASE_REG,
- 1, I8254_MODE0);
- }
- if (ret) {
- comedi_error(dev, "error loading counter a1");
- return ret;
+ labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG,
+ 1, I8254_MODE0);
}
/* figure out what method we will use to transfer data */
@@ -805,38 +799,25 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* set up pacing */
labpc_adc_timing(dev, cmd, mode);
/* load counter b0 in mode 3 */
- ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
- 0, devpriv->divisor_b0, I8254_MODE3);
- if (ret < 0) {
- comedi_error(dev, "error loading counter b0");
- return -1;
- }
+ labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
+ 0, devpriv->divisor_b0, I8254_MODE3);
}
/* set up conversion pacing */
if (labpc_ai_convert_period(cmd, mode)) {
/* load counter a0 in mode 2 */
- ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG,
- 0, devpriv->divisor_a0, I8254_MODE2);
+ labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG,
+ 0, devpriv->divisor_a0, I8254_MODE2);
} else {
/* initialize pacer counter to prevent any problems */
- ret = labpc_counter_set_mode(dev,
- dev->iobase + COUNTER_A_BASE_REG,
- 0, I8254_MODE2);
- }
- if (ret) {
- comedi_error(dev, "error loading counter a0");
- return ret;
+ labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG,
+ 0, I8254_MODE2);
}
/* set up scan pacing */
if (labpc_ai_scan_period(cmd, mode)) {
/* load counter b1 in mode 2 */
- ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
- 1, devpriv->divisor_b1, I8254_MODE2);
- if (ret < 0) {
- comedi_error(dev, "error loading counter b1");
- return -1;
- }
+ labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
+ 1, devpriv->divisor_b1, I8254_MODE2);
}
labpc_clear_adc_fifo(dev);
@@ -893,8 +874,9 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
static int labpc_drain_fifo(struct comedi_device *dev)
{
struct labpc_private *devpriv = dev->private;
- unsigned short data;
struct comedi_async *async = dev->read_subdev->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ unsigned short data;
const int timeout = 10000;
unsigned int i;
@@ -903,7 +885,7 @@ static int labpc_drain_fifo(struct comedi_device *dev)
for (i = 0; (devpriv->stat1 & STAT1_DAVAIL) && i < timeout;
i++) {
/* quit if we have all the data we want */
- if (async->cmd.stop_src == TRIG_COUNT) {
+ if (cmd->stop_src == TRIG_COUNT) {
if (devpriv->count == 0)
break;
devpriv->count--;
@@ -950,7 +932,6 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
async = s->async;
cmd = &async->cmd;
- async->events = 0;
/* read board status */
devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
@@ -968,7 +949,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
/* clear error interrupt */
devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
comedi_error(dev, "overrun");
return IRQ_HANDLED;
}
@@ -988,7 +969,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
/* clear error interrupt */
devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG);
async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
comedi_error(dev, "overflow");
return IRQ_HANDLED;
}
@@ -996,20 +977,17 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
if (cmd->stop_src == TRIG_EXT) {
if (devpriv->stat2 & STAT2_OUTA1) {
labpc_drain_dregs(dev);
- labpc_cancel(dev, s);
async->events |= COMEDI_CB_EOA;
}
}
/* TRIG_COUNT end of acquisition */
if (cmd->stop_src == TRIG_COUNT) {
- if (devpriv->count == 0) {
- labpc_cancel(dev, s);
+ if (devpriv->count == 0)
async->events |= COMEDI_CB_EOA;
- }
}
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.c b/drivers/staging/comedi/drivers/ni_labpc_isadma.c
index 2149596830a..d9f25fdbb72 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_isadma.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.c
@@ -87,6 +87,7 @@ void labpc_drain_dma(struct comedi_device *dev)
struct labpc_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
int status;
unsigned long flags;
unsigned int max_points, num_points, residue, leftover;
@@ -108,12 +109,12 @@ void labpc_drain_dma(struct comedi_device *dev)
*/
residue = get_dma_residue(devpriv->dma_chan) / sample_size;
num_points = max_points - residue;
- if (devpriv->count < num_points && async->cmd.stop_src == TRIG_COUNT)
+ if (cmd->stop_src == TRIG_COUNT && devpriv->count < num_points)
num_points = devpriv->count;
/* figure out how many points will be stored next time */
leftover = 0;
- if (async->cmd.stop_src != TRIG_COUNT) {
+ if (cmd->stop_src != TRIG_COUNT) {
leftover = devpriv->dma_transfer_size / sample_size;
} else if (devpriv->count > num_points) {
leftover = devpriv->count - num_points;
@@ -125,7 +126,7 @@ void labpc_drain_dma(struct comedi_device *dev)
for (i = 0; i < num_points; i++)
cfc_write_to_buffer(s, devpriv->dma_buffer[i]);
- if (async->cmd.stop_src == TRIG_COUNT)
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->count -= num_points;
/* set address and count for next transfer */
diff --git a/drivers/staging/comedi/drivers/ni_labpc_pci.c b/drivers/staging/comedi/drivers/ni_labpc_pci.c
index 8be681fca90..73959706829 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_pci.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_pci.c
@@ -107,7 +107,7 @@ static struct comedi_driver labpc_pci_comedi_driver = {
.detach = labpc_pci_detach,
};
-static DEFINE_PCI_DEVICE_TABLE(labpc_pci_table) = {
+static const struct pci_device_id labpc_pci_table[] = {
{ PCI_VDEVICE(NI, 0x161), BOARD_NI_PCI1200 },
{ 0 }
};
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index 5113397bfec..7ffdcc07ef9 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -52,10 +52,6 @@
fully tested as yet. Terry Barnaby, BEAM Ltd.
*/
-/* #define DEBUG_INTERRUPT */
-/* #define DEBUG_STATUS_A */
-/* #define DEBUG_STATUS_B */
-
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/delay.h>
@@ -63,10 +59,6 @@
#include "mite.h"
#include "comedi_fc.h"
-#ifndef MDPRINTK
-#define MDPRINTK(format, args...)
-#endif
-
/* A timeout count */
#define NI_TIMEOUT 1000
static const unsigned old_RTSI_clock_channel = 7;
@@ -86,111 +78,109 @@ static const short ni_gainlkup[][16] = {
[ai_gain_6143] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
};
-static const struct comedi_lrange range_ni_E_ai = { 16, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-2.5, 2.5),
- RANGE(-1, 1),
- RANGE(-0.5, 0.5),
- RANGE(-0.25, 0.25),
- RANGE(-0.1, 0.1),
- RANGE(-0.05, 0.05),
- RANGE(0, 20),
- RANGE(0, 10),
- RANGE(0, 5),
- RANGE(0, 2),
- RANGE(0, 1),
- RANGE(0, 0.5),
- RANGE(0, 0.2),
- RANGE(0, 0.1),
- }
+static const struct comedi_lrange range_ni_E_ai = {
+ 16, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.25),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.05),
+ UNI_RANGE(20),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2),
+ UNI_RANGE(1),
+ UNI_RANGE(0.5),
+ UNI_RANGE(0.2),
+ UNI_RANGE(0.1)
+ }
};
-static const struct comedi_lrange range_ni_E_ai_limited = { 8, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-1, 1),
- RANGE(-0.1,
- 0.1),
- RANGE(0, 10),
- RANGE(0, 5),
- RANGE(0, 1),
- RANGE(0, 0.1),
- }
+static const struct comedi_lrange range_ni_E_ai_limited = {
+ 8, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(1),
+ BIP_RANGE(0.1),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1)
+ }
};
-static const struct comedi_lrange range_ni_E_ai_limited14 = { 14, {
- RANGE(-10,
- 10),
- RANGE(-5, 5),
- RANGE(-2, 2),
- RANGE(-1, 1),
- RANGE(-0.5,
- 0.5),
- RANGE(-0.2,
- 0.2),
- RANGE(-0.1,
- 0.1),
- RANGE(0, 10),
- RANGE(0, 5),
- RANGE(0, 2),
- RANGE(0, 1),
- RANGE(0,
- 0.5),
- RANGE(0,
- 0.2),
- RANGE(0,
- 0.1),
- }
+static const struct comedi_lrange range_ni_E_ai_limited14 = {
+ 14, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.2),
+ BIP_RANGE(0.1),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2),
+ UNI_RANGE(1),
+ UNI_RANGE(0.5),
+ UNI_RANGE(0.2),
+ UNI_RANGE(0.1)
+ }
};
-static const struct comedi_lrange range_ni_E_ai_bipolar4 = { 4, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-0.5,
- 0.5),
- RANGE(-0.05,
- 0.05),
- }
+static const struct comedi_lrange range_ni_E_ai_bipolar4 = {
+ 4, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.05)
+ }
};
-static const struct comedi_lrange range_ni_E_ai_611x = { 8, {
- RANGE(-50, 50),
- RANGE(-20, 20),
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-2, 2),
- RANGE(-1, 1),
- RANGE(-0.5, 0.5),
- RANGE(-0.2, 0.2),
- }
+static const struct comedi_lrange range_ni_E_ai_611x = {
+ 8, {
+ BIP_RANGE(50),
+ BIP_RANGE(20),
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.2)
+ }
};
-static const struct comedi_lrange range_ni_M_ai_622x = { 4, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-1, 1),
- RANGE(-0.2, 0.2),
- }
+static const struct comedi_lrange range_ni_M_ai_622x = {
+ 4, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(1),
+ BIP_RANGE(0.2)
+ }
};
-static const struct comedi_lrange range_ni_M_ai_628x = { 7, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-2, 2),
- RANGE(-1, 1),
- RANGE(-0.5, 0.5),
- RANGE(-0.2, 0.2),
- RANGE(-0.1, 0.1),
- }
+static const struct comedi_lrange range_ni_M_ai_628x = {
+ 7, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.2),
+ BIP_RANGE(0.1)
+ }
};
-static const struct comedi_lrange range_ni_E_ao_ext = { 4, {
- RANGE(-10, 10),
- RANGE(0, 10),
- RANGE_ext(-1, 1),
- RANGE_ext(0, 1),
- }
+static const struct comedi_lrange range_ni_E_ao_ext = {
+ 4, {
+ BIP_RANGE(10),
+ UNI_RANGE(10),
+ RANGE_ext(-1, 1),
+ RANGE_ext(0, 1)
+ }
};
static const struct comedi_lrange *const ni_range_lkup[] = {
@@ -266,18 +256,6 @@ static int ni_rtsi_insn_config(struct comedi_device *dev,
static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s);
static int ni_read_eeprom(struct comedi_device *dev, int addr);
-#ifdef DEBUG_STATUS_A
-static void ni_mio_print_status_a(int status);
-#else
-#define ni_mio_print_status_a(a)
-#endif
-#ifdef DEBUG_STATUS_B
-static void ni_mio_print_status_b(int status);
-#else
-#define ni_mio_print_status_b(a)
-#endif
-
-static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s);
#ifndef PCIDMA
static void ni_handle_fifo_half_full(struct comedi_device *dev);
static int ni_ao_fifo_half_empty(struct comedi_device *dev,
@@ -293,26 +271,12 @@ static void shutdown_ai_command(struct comedi_device *dev);
static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned int trignum);
-static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s);
-
static int ni_8255_callback(int dir, int port, int data, unsigned long arg);
-static int ni_gpct_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int ni_gpct_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int ni_gpct_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
#ifdef PCIDMA
static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int ni_gpct_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd);
+static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
#endif
-static int ni_gpct_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
static void handle_gpct_interrupt(struct comedi_device *dev,
unsigned short counter_index);
@@ -322,10 +286,6 @@ static int cs5529_do_conversion(struct comedi_device *dev,
static int cs5529_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
-#ifdef NI_CS5529_DEBUG
-static unsigned int cs5529_config_read(struct comedi_device *dev,
- unsigned int reg_select_bits);
-#endif
static void cs5529_config_write(struct comedi_device *dev, unsigned int value,
unsigned int reg_select_bits);
@@ -487,11 +447,10 @@ static inline void ni_set_gpct_dma_channel(struct comedi_device *dev,
{
unsigned bitfield;
- if (mite_channel >= 0) {
+ if (mite_channel >= 0)
bitfield = GPCT_DMA_Select_Bits(gpct_index, mite_channel);
- } else {
+ else
bitfield = 0;
- }
ni_set_bitfield(dev, G0_G1_Select, GPCT_DMA_Select_Mask(gpct_index),
bitfield);
}
@@ -724,12 +683,22 @@ static void ni_clear_ai_fifo(struct comedi_device *dev)
{
const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
+ static const int timeout = 10000;
+ int i;
if (board->reg_type == ni_reg_6143) {
/* Flush the 6143 data FIFO */
ni_writel(0x10, AIFIFO_Control_6143); /* Flush fifo */
ni_writel(0x00, AIFIFO_Control_6143); /* Flush fifo */
- while (ni_readl(AIFIFO_Status_6143) & 0x10) ; /* Wait for complete */
+ /* Wait for complete */
+ for (i = 0; i < timeout; i++) {
+ if (!(ni_readl(AIFIFO_Status_6143) & 0x10))
+ break;
+ udelay(1);
+ }
+ if (i == timeout) {
+ comedi_error(dev, "FIFO flush timeout.");
+ }
} else {
devpriv->stc_writew(dev, 1, ADC_FIFO_Clear);
if (board->reg_type == ni_reg_625x) {
@@ -895,7 +864,7 @@ static void ni_sync_ai_dma(struct comedi_device *dev)
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
if (devpriv->ai_mite_chan)
- mite_sync_input_dma(devpriv->ai_mite_chan, s->async);
+ mite_sync_input_dma(devpriv->ai_mite_chan, s);
spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
}
@@ -907,9 +876,8 @@ static void mite_handle_b_linkc(struct mite_struct *mite,
unsigned long flags;
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
- if (devpriv->ao_mite_chan) {
- mite_sync_output_dma(devpriv->ao_mite_chan, s->async);
- }
+ if (devpriv->ao_mite_chan)
+ mite_sync_output_dma(devpriv->ao_mite_chan, s);
spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
}
@@ -957,9 +925,8 @@ static void ni_handle_eos(struct comedi_device *dev, struct comedi_subdevice *s)
#endif
}
/* handle special case of single scan using AI_End_On_End_Of_Scan */
- if ((devpriv->ai_cmd2 & AI_End_On_End_Of_Scan)) {
+ if ((devpriv->ai_cmd2 & AI_End_On_End_Of_Scan))
shutdown_ai_command(dev);
- }
}
static void shutdown_ai_command(struct comedi_device *dev)
@@ -976,32 +943,6 @@ static void shutdown_ai_command(struct comedi_device *dev)
s->async->events |= COMEDI_CB_EOA;
}
-static void ni_event(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- if (s->
- async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW |
- COMEDI_CB_EOA)) {
- switch (s->index) {
- case NI_AI_SUBDEV:
- ni_ai_reset(dev, s);
- break;
- case NI_AO_SUBDEV:
- ni_ao_reset(dev, s);
- break;
- case NI_GPCT0_SUBDEV:
- case NI_GPCT1_SUBDEV:
- ni_gpct_cancel(dev, s);
- break;
- case NI_DIO_SUBDEV:
- ni_cdio_cancel(dev, s);
- break;
- default:
- break;
- }
- }
- comedi_event(dev, s);
-}
-
static void handle_gpct_interrupt(struct comedi_device *dev,
unsigned short counter_index)
{
@@ -1013,8 +954,7 @@ static void handle_gpct_interrupt(struct comedi_device *dev,
ni_tio_handle_interrupt(&devpriv->counter_dev->counters[counter_index],
s);
- if (s->async->events)
- ni_event(dev, s);
+ cfc_handle_events(dev, s);
#endif
}
@@ -1023,19 +963,15 @@ static void ack_a_interrupt(struct comedi_device *dev, unsigned short a_status)
struct ni_private *devpriv = dev->private;
unsigned short ack = 0;
- if (a_status & AI_SC_TC_St) {
+ if (a_status & AI_SC_TC_St)
ack |= AI_SC_TC_Interrupt_Ack;
- }
- if (a_status & AI_START1_St) {
+ if (a_status & AI_START1_St)
ack |= AI_START1_Interrupt_Ack;
- }
- if (a_status & AI_START_St) {
+ if (a_status & AI_START_St)
ack |= AI_START_Interrupt_Ack;
- }
- if (a_status & AI_STOP_St) {
+ if (a_status & AI_STOP_St)
/* not sure why we used to ack the START here also, instead of doing it independently. Frank Hess 2007-07-06 */
- ack |= AI_STOP_Interrupt_Ack /*| AI_START_Interrupt_Ack */ ;
- }
+ ack |= AI_STOP_Interrupt_Ack /*| AI_START_Interrupt_Ack */;
if (ack)
devpriv->stc_writew(dev, ack, Interrupt_A_Ack_Register);
}
@@ -1050,16 +986,9 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
if (s->type == COMEDI_SUBD_UNUSED)
return;
-#ifdef DEBUG_INTERRUPT
- printk
- ("ni_mio_common: interrupt: a_status=%04x ai_mite_status=%08x\n",
- status, ai_mite_status);
- ni_mio_print_status_a(status);
-#endif
#ifdef PCIDMA
- if (ai_mite_status & CHSR_LINKC) {
+ if (ai_mite_status & CHSR_LINKC)
ni_sync_ai_dma(dev);
- }
if (ai_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY |
CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR |
@@ -1067,7 +996,6 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
printk
("unknown mite interrupt, ack! (ai_mite_status=%08x)\n",
ai_mite_status);
- /* mite_print_chsr(ai_mite_status); */
s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
/* disable_irq(dev->irq); */
}
@@ -1084,7 +1012,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
if (comedi_is_subdevice_running(s)) {
s->async->events |=
COMEDI_CB_ERROR | COMEDI_CB_EOA;
- ni_event(dev, s);
+ cfc_handle_events(dev, s);
}
return;
}
@@ -1092,7 +1020,6 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
AI_SC_TC_Error_St)) {
printk("ni_mio_common: ai error a_status=%04x\n",
status);
- ni_mio_print_status_a(status);
shutdown_ai_command(dev);
@@ -1100,17 +1027,12 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
if (status & (AI_Overrun_St | AI_Overflow_St))
s->async->events |= COMEDI_CB_OVERFLOW;
- ni_event(dev, s);
-
+ cfc_handle_events(dev, s);
return;
}
if (status & AI_SC_TC_St) {
-#ifdef DEBUG_INTERRUPT
- printk("ni_mio_common: SC_TC interrupt\n");
-#endif
- if (!devpriv->ai_continuous) {
+ if (!devpriv->ai_continuous)
shutdown_ai_command(dev);
- }
}
}
#ifndef PCIDMA
@@ -1129,20 +1051,10 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
}
#endif /* !PCIDMA */
- if ((status & AI_STOP_St)) {
+ if ((status & AI_STOP_St))
ni_handle_eos(dev, s);
- }
- ni_event(dev, s);
-
-#ifdef DEBUG_INTERRUPT
- status = devpriv->stc_readw(dev, AI_Status_1_Register);
- if (status & Interrupt_A_St) {
- printk
- ("handle_a_interrupt: didn't clear interrupt? status=0x%x\n",
- status);
- }
-#endif
+ cfc_handle_events(dev, s);
}
static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status)
@@ -1150,27 +1062,20 @@ static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status)
struct ni_private *devpriv = dev->private;
unsigned short ack = 0;
- if (b_status & AO_BC_TC_St) {
+ if (b_status & AO_BC_TC_St)
ack |= AO_BC_TC_Interrupt_Ack;
- }
- if (b_status & AO_Overrun_St) {
+ if (b_status & AO_Overrun_St)
ack |= AO_Error_Interrupt_Ack;
- }
- if (b_status & AO_START_St) {
+ if (b_status & AO_START_St)
ack |= AO_START_Interrupt_Ack;
- }
- if (b_status & AO_START1_St) {
+ if (b_status & AO_START1_St)
ack |= AO_START1_Interrupt_Ack;
- }
- if (b_status & AO_UC_TC_St) {
+ if (b_status & AO_UC_TC_St)
ack |= AO_UC_TC_Interrupt_Ack;
- }
- if (b_status & AO_UI2_TC_St) {
+ if (b_status & AO_UI2_TC_St)
ack |= AO_UI2_TC_Interrupt_Ack;
- }
- if (b_status & AO_UPDATE_St) {
+ if (b_status & AO_UPDATE_St)
ack |= AO_UPDATE_Interrupt_Ack;
- }
if (ack)
devpriv->stc_writew(dev, ack, Interrupt_B_Ack_Register);
}
@@ -1182,17 +1087,10 @@ static void handle_b_interrupt(struct comedi_device *dev,
struct comedi_subdevice *s = &dev->subdevices[NI_AO_SUBDEV];
/* unsigned short ack=0; */
-#ifdef DEBUG_INTERRUPT
- printk("ni_mio_common: interrupt: b_status=%04x m1_status=%08x\n",
- b_status, ao_mite_status);
- ni_mio_print_status_b(b_status);
-#endif
-
#ifdef PCIDMA
/* Currently, mite.c requires us to handle LINKC */
- if (ao_mite_status & CHSR_LINKC) {
+ if (ao_mite_status & CHSR_LINKC)
mite_handle_b_linkc(devpriv->mite, dev);
- }
if (ao_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY |
CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR |
@@ -1200,7 +1098,6 @@ static void handle_b_interrupt(struct comedi_device *dev,
printk
("unknown mite interrupt, ack! (ao_mite_status=%08x)\n",
ao_mite_status);
- /* mite_print_chsr(ao_mite_status); */
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
}
#endif
@@ -1214,12 +1111,9 @@ static void handle_b_interrupt(struct comedi_device *dev,
s->async->events |= COMEDI_CB_OVERFLOW;
}
- if (b_status & AO_BC_TC_St) {
- MDPRINTK
- ("ni_mio_common: AO BC_TC status=0x%04x status2=0x%04x\n",
- b_status, devpriv->stc_readw(dev, AO_Status_2_Register));
+ if (b_status & AO_BC_TC_St)
s->async->events |= COMEDI_CB_EOA;
- }
+
#ifndef PCIDMA
if (b_status & AO_FIFO_Request_St) {
int ret;
@@ -1235,52 +1129,8 @@ static void handle_b_interrupt(struct comedi_device *dev,
}
#endif
- ni_event(dev, s);
-}
-
-#ifdef DEBUG_STATUS_A
-static const char *const status_a_strings[] = {
- "passthru0", "fifo", "G0_gate", "G0_TC",
- "stop", "start", "sc_tc", "start1",
- "start2", "sc_tc_error", "overflow", "overrun",
- "fifo_empty", "fifo_half_full", "fifo_full", "interrupt_a"
-};
-
-static void ni_mio_print_status_a(int status)
-{
- int i;
-
- printk("A status:");
- for (i = 15; i >= 0; i--) {
- if (status & (1 << i)) {
- printk(" %s", status_a_strings[i]);
- }
- }
- printk("\n");
-}
-#endif
-
-#ifdef DEBUG_STATUS_B
-static const char *const status_b_strings[] = {
- "passthru1", "fifo", "G1_gate", "G1_TC",
- "UI2_TC", "UPDATE", "UC_TC", "BC_TC",
- "start1", "overrun", "start", "bc_tc_error",
- "fifo_empty", "fifo_half_full", "fifo_full", "interrupt_b"
-};
-
-static void ni_mio_print_status_b(int status)
-{
- int i;
-
- printk("B status:");
- for (i = 15; i >= 0; i--) {
- if (status & (1 << i)) {
- printk(" %s", status_b_strings[i]);
- }
- }
- printk("\n");
+ cfc_handle_events(dev, s);
}
-#endif
#ifndef PCIDMA
@@ -1299,7 +1149,7 @@ static void ni_ao_fifo_load(struct comedi_device *dev,
chan = async->cur_chan;
for (i = 0; i < n; i++) {
- err &= comedi_buf_get(async, &d);
+ err &= comedi_buf_get(s, &d);
if (err == 0)
break;
@@ -1309,7 +1159,7 @@ static void ni_ao_fifo_load(struct comedi_device *dev,
packed_data = d & 0xffff;
/* 6711 only has 16 bit wide ao fifo */
if (board->reg_type != ni_reg_6711) {
- err &= comedi_buf_get(async, &d);
+ err &= comedi_buf_get(s, &d);
if (err == 0)
break;
chan++;
@@ -1324,9 +1174,8 @@ static void ni_ao_fifo_load(struct comedi_device *dev,
chan %= cmd->chanlist_len;
}
async->cur_chan = chan;
- if (err == 0) {
+ if (err == 0)
async->events |= COMEDI_CB_OVERFLOW;
- }
}
/*
@@ -1351,7 +1200,7 @@ static int ni_ao_fifo_half_empty(struct comedi_device *dev,
const struct ni_board_struct *board = comedi_board(dev);
int n;
- n = comedi_buf_read_n_available(s->async);
+ n = comedi_buf_read_n_available(s);
if (n == 0) {
s->async->events |= COMEDI_CB_OVERFLOW;
return 0;
@@ -1381,7 +1230,7 @@ static int ni_ao_prep_fifo(struct comedi_device *dev,
ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x);
/* load some data */
- n = comedi_buf_read_n_available(s->async);
+ n = comedi_buf_read_n_available(s);
if (n == 0)
return 0;
@@ -1619,10 +1468,11 @@ static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s,
{
struct ni_private *devpriv = dev->private;
struct comedi_async *async = s->async;
- unsigned int i;
+ struct comedi_cmd *cmd = &async->cmd;
unsigned int length = num_bytes / bytes_per_sample(s);
unsigned short *array = data;
unsigned int *larray = data;
+ unsigned int i;
for (i = 0; i < length; i++) {
#ifdef PCIDMA
@@ -1636,7 +1486,7 @@ static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s,
else
array[i] += devpriv->ai_offset[chan_index];
chan_index++;
- chan_index %= async->cmd.chanlist_len;
+ chan_index %= cmd->chanlist_len;
}
}
@@ -1656,7 +1506,7 @@ static int ni_ai_setup_MITE_dma(struct comedi_device *dev)
/* printk("comedi_debug: using mite channel %i for ai.\n", devpriv->ai_mite_chan->channel); */
/* write alloc the entire buffer */
- comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
+ comedi_buf_write_alloc(s, s->async->prealloc_bufsz);
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
if (devpriv->ai_mite_chan == NULL) {
@@ -1696,7 +1546,7 @@ static int ni_ao_setup_MITE_dma(struct comedi_device *dev)
return retval;
/* read alloc the entire buffer */
- comedi_buf_read_alloc(s->async, s->async->prealloc_bufsz);
+ comedi_buf_read_alloc(s, s->async->prealloc_bufsz);
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
if (devpriv->ao_mite_chan) {
@@ -2231,7 +2081,7 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
int err = 0;
- int tmp;
+ unsigned int tmp;
unsigned int sources;
/* Step 1 : check if triggers are trivially valid */
@@ -2270,17 +2120,19 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
/* Step 3: check if arguments are trivially valid */
- if (cmd->start_src == TRIG_EXT) {
- /* external trigger */
- unsigned int tmp = CR_CHAN(cmd->start_arg);
+ switch (cmd->start_src) {
+ case TRIG_NOW:
+ case TRIG_INT:
+ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ break;
+ case TRIG_EXT:
+ tmp = CR_CHAN(cmd->start_arg);
if (tmp > 16)
tmp = 16;
tmp |= (cmd->start_arg & (CR_INVERT | CR_EDGE));
err |= cfc_check_trigger_arg_is(&cmd->start_arg, tmp);
- } else {
- /* true for both TRIG_NOW and TRIG_INT */
- err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ break;
}
if (cmd->scan_begin_src == TRIG_TIMER) {
@@ -2392,7 +2244,6 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
unsigned int stop_count;
int interrupt_a_enable = 0;
- MDPRINTK("ni_ai_cmd\n");
if (dev->irq == 0) {
comedi_error(dev, "cannot run command without an irq");
return -EIO;
@@ -2630,15 +2481,11 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
ni_set_bits(dev, Interrupt_A_Enable_Register,
interrupt_a_enable, 1);
-
- MDPRINTK("Interrupt_A_Enable_Register = 0x%04x\n",
- devpriv->int_a_enable_reg);
} else {
/* interrupt on nothing */
ni_set_bits(dev, Interrupt_A_Enable_Register, ~0, 0);
/* XXX start polling if necessary */
- MDPRINTK("interrupting on nothing\n");
}
/* end configuration */
@@ -2664,35 +2511,30 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (retval)
return retval;
}
- /* mite_dump_regs(devpriv->mite); */
#endif
- switch (cmd->start_src) {
- case TRIG_NOW:
+ if (cmd->start_src == TRIG_NOW) {
/* AI_START1_Pulse */
devpriv->stc_writew(dev, AI_START1_Pulse | devpriv->ai_cmd2,
AI_Command_2_Register);
s->async->inttrig = NULL;
- break;
- case TRIG_EXT:
+ } else if (cmd->start_src == TRIG_EXT) {
s->async->inttrig = NULL;
- break;
- case TRIG_INT:
- s->async->inttrig = &ni_ai_inttrig;
- break;
+ } else { /* TRIG_INT */
+ s->async->inttrig = ni_ai_inttrig;
}
- MDPRINTK("exit ni_ai_cmd\n");
-
return 0;
}
-static int ni_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int trignum)
+static int ni_ai_inttrig(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int trig_num)
{
struct ni_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
- if (trignum != 0)
+ if (trig_num != cmd->start_arg)
return -EINVAL;
devpriv->stc_writew(dev, AI_START1_Pulse | devpriv->ai_cmd2,
@@ -2869,22 +2711,22 @@ static void ni_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
{
const struct ni_board_struct *board = comedi_board(dev);
struct comedi_async *async = s->async;
- unsigned int range;
- unsigned int i;
- unsigned int offset;
+ struct comedi_cmd *cmd = &async->cmd;
unsigned int length = num_bytes / sizeof(short);
+ unsigned int offset = 1 << (board->aobits - 1);
unsigned short *array = data;
+ unsigned int range;
+ unsigned int i;
- offset = 1 << (board->aobits - 1);
for (i = 0; i < length; i++) {
- range = CR_RANGE(async->cmd.chanlist[chan_index]);
+ range = CR_RANGE(cmd->chanlist[chan_index]);
if (board->ao_unipolar == 0 || (range & 1) == 0)
array[i] -= offset;
#ifdef PCIDMA
array[i] = cpu_to_le16(array[i]);
#endif
chan_index++;
- chan_index %= async->cmd.chanlist_len;
+ chan_index %= cmd->chanlist_len;
}
}
@@ -3105,17 +2947,19 @@ static int ni_ao_insn_config(struct comedi_device *dev,
return -EINVAL;
}
-static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int trignum)
+static int ni_ao_inttrig(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int trig_num)
{
const struct ni_board_struct *board __maybe_unused = comedi_board(dev);
struct ni_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
int ret;
int interrupt_b_bits;
int i;
static const int timeout = 1000;
- if (trignum != 0)
+ if (trig_num != cmd->start_arg)
return -EINVAL;
/* Null trig at beginning prevent ao start trigger from executing more than
@@ -3248,11 +3092,10 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->stc_writew(dev, devpriv->ao_mode1, AO_Mode_1_Register);
devpriv->ao_mode2 &= ~AO_BC_Initial_Load_Source;
devpriv->stc_writew(dev, devpriv->ao_mode2, AO_Mode_2_Register);
- if (cmd->stop_src == TRIG_NONE) {
+ if (cmd->stop_src == TRIG_NONE)
devpriv->stc_writel(dev, 0xffffff, AO_BC_Load_A_Register);
- } else {
+ else
devpriv->stc_writel(dev, 0, AO_BC_Load_A_Register);
- }
devpriv->stc_writew(dev, AO_BC_Load, AO_Command_1_Register);
devpriv->ao_mode2 &= ~AO_UC_Initial_Load_Source;
devpriv->stc_writew(dev, devpriv->ao_mode2, AO_Mode_2_Register);
@@ -3377,7 +3220,7 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
AO_BC_TC_Interrupt_Enable, 1);
}
- s->async->inttrig = &ni_ao_inttrig;
+ s->async->inttrig = ni_ao_inttrig;
return 0;
}
@@ -3388,7 +3231,7 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
int err = 0;
- int tmp;
+ unsigned int tmp;
/* Step 1 : check if triggers are trivially valid */
@@ -3418,17 +3261,18 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
/* Step 3: check if arguments are trivially valid */
- if (cmd->start_src == TRIG_EXT) {
- /* external trigger */
- unsigned int tmp = CR_CHAN(cmd->start_arg);
+ switch (cmd->start_src) {
+ case TRIG_INT:
+ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ break;
+ case TRIG_EXT:
+ tmp = CR_CHAN(cmd->start_arg);
if (tmp > 18)
tmp = 18;
tmp |= (cmd->start_arg & (CR_INVERT | CR_EDGE));
err |= cfc_check_trigger_arg_is(&cmd->start_arg, tmp);
- } else {
- /* true for both TRIG_NOW and TRIG_INT */
- err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ break;
}
if (cmd->scan_begin_src == TRIG_TIMER) {
@@ -3464,11 +3308,6 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
if (err)
return 4;
- /* step 5: fix up chanlist */
-
- if (err)
- return 5;
-
return 0;
}
@@ -3513,9 +3352,8 @@ static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s)
if (board->reg_type & ni_reg_6xxx_mask) {
unsigned immediate_bits = 0;
unsigned i;
- for (i = 0; i < s->n_chan; ++i) {
+ for (i = 0; i < s->n_chan; ++i)
immediate_bits |= 1 << i;
- }
ao_win_out(immediate_bits, AO_Immediate_671x);
ao_win_out(CLEAR_WG, AO_Misc_611x);
}
@@ -3600,12 +3438,27 @@ static int ni_m_series_dio_insn_bits(struct comedi_device *dev,
return insn->n;
}
+static int ni_cdio_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ int i;
+
+ for (i = 0; i < cmd->chanlist_len; ++i) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+
+ if (chan != i)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int ni_cdio_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
int err = 0;
int tmp;
- unsigned i;
/* Step 1 : check if triggers are trivially valid */
@@ -3645,12 +3498,9 @@ static int ni_cdio_cmdtest(struct comedi_device *dev,
if (err)
return 4;
- /* step 5: check chanlist */
-
- for (i = 0; i < cmd->chanlist_len; ++i) {
- if (cmd->chanlist[i] != i)
- err = 1;
- }
+ /* Step 5: check channel list if it exists */
+ if (cmd->chanlist && cmd->chanlist_len > 0)
+ err |= ni_cdio_check_chanlist(dev, s, cmd);
if (err)
return 5;
@@ -3689,28 +3539,34 @@ static int ni_cdio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
return -EIO;
}
retval = ni_request_cdo_mite_channel(dev);
- if (retval < 0) {
+ if (retval < 0)
return retval;
- }
- s->async->inttrig = &ni_cdo_inttrig;
+
+ s->async->inttrig = ni_cdo_inttrig;
+
return 0;
}
-static int ni_cdo_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int trignum)
+static int ni_cdo_inttrig(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int trig_num)
{
#ifdef PCIDMA
struct ni_private *devpriv = dev->private;
unsigned long flags;
#endif
+ struct comedi_cmd *cmd = &s->async->cmd;
int retval = 0;
unsigned i;
const unsigned timeout = 1000;
+ if (trig_num != cmd->start_arg)
+ return -EINVAL;
+
s->async->inttrig = NULL;
/* read alloc the entire buffer */
- comedi_buf_read_alloc(s->async, s->async->prealloc_bufsz);
+ comedi_buf_read_alloc(s, s->async->prealloc_bufsz);
#ifdef PCIDMA
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
@@ -3773,9 +3629,8 @@ static void handle_cdio_interrupt(struct comedi_device *dev)
unsigned long flags;
#endif
- if ((board->reg_type & ni_reg_m_series_mask) == 0) {
+ if ((board->reg_type & ni_reg_m_series_mask) == 0)
return;
- }
#ifdef PCIDMA
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
if (devpriv->cdo_mite_chan) {
@@ -3786,24 +3641,24 @@ static void handle_cdio_interrupt(struct comedi_device *dev)
devpriv->mite->mite_io_addr +
MITE_CHOR(devpriv->cdo_mite_chan->channel));
}
- mite_sync_output_dma(devpriv->cdo_mite_chan, s->async);
+ mite_sync_output_dma(devpriv->cdo_mite_chan, s);
}
spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
#endif
cdio_status = ni_readl(M_Offset_CDIO_Status);
if (cdio_status & (CDO_Overrun_Bit | CDO_Underflow_Bit)) {
-/* printk("cdio error: statux=0x%x\n", cdio_status); */
+ /* printk("cdio error: statux=0x%x\n", cdio_status); */
ni_writel(CDO_Error_Interrupt_Confirm_Bit, M_Offset_CDIO_Command); /* XXX just guessing this is needed and does something useful */
s->async->events |= COMEDI_CB_OVERFLOW;
}
if (cdio_status & CDO_FIFO_Empty_Bit) {
-/* printk("cdio fifo empty\n"); */
+ /* printk("cdio fifo empty\n"); */
ni_writel(CDO_Empty_FIFO_Interrupt_Enable_Clear_Bit,
M_Offset_CDIO_Command);
-/* s->async->events |= COMEDI_CB_EOA; */
+ /* s->async->events |= COMEDI_CB_EOA; */
}
- ni_event(dev, s);
+ cfc_handle_events(dev, s);
}
static int ni_serial_insn_config(struct comedi_device *dev,
@@ -3819,10 +3674,6 @@ static int ni_serial_insn_config(struct comedi_device *dev,
switch (data[0]) {
case INSN_CONFIG_SERIAL_CLOCK:
-
-#ifdef DEBUG_DIO
- printk("SPI serial clock Config cd\n", data[1]);
-#endif
devpriv->serial_hw_mode = 1;
devpriv->dio_control |= DIO_HW_Serial_Enable;
@@ -3874,9 +3725,8 @@ static int ni_serial_insn_config(struct comedi_device *dev,
case INSN_CONFIG_BIDIRECTIONAL_DATA:
- if (devpriv->serial_interval_ns == 0) {
+ if (devpriv->serial_interval_ns == 0)
return -EINVAL;
- }
byte_out = data[1] & 0xFF;
@@ -3911,10 +3761,6 @@ static int ni_serial_hw_readwrite8(struct comedi_device *dev,
unsigned int status1;
int err = 0, count = 20;
-#ifdef DEBUG_DIO
- printk("ni_serial_hw_readwrite8: outputting 0x%x\n", data_out);
-#endif
-
devpriv->dio_output &= ~DIO_Serial_Data_Mask;
devpriv->dio_output |= DIO_Serial_Data_Out(data_out);
devpriv->stc_writew(dev, devpriv->dio_output, DIO_Output_Register);
@@ -3948,12 +3794,8 @@ static int ni_serial_hw_readwrite8(struct comedi_device *dev,
DIO_Serial_IO_In_Progress_St goes high one bit too early. */
udelay((devpriv->serial_interval_ns + 999) / 1000);
- if (data_in != NULL) {
+ if (data_in != NULL)
*data_in = devpriv->stc_readw(dev, DIO_Serial_Input_Register);
-#ifdef DEBUG_DIO
- printk("ni_serial_hw_readwrite8: inputted 0x%x\n", *data_in);
-#endif
- }
Error:
devpriv->stc_writew(dev, devpriv->dio_control, DIO_Control_Register);
@@ -3969,10 +3811,6 @@ static int ni_serial_sw_readwrite8(struct comedi_device *dev,
struct ni_private *devpriv = dev->private;
unsigned char mask, input = 0;
-#ifdef DEBUG_DIO
- printk("ni_serial_sw_readwrite8: outputting 0x%x\n", data_out);
-#endif
-
/* Wait for one bit before transfer */
udelay((devpriv->serial_interval_ns + 999) / 1000);
@@ -3981,9 +3819,8 @@ static int ni_serial_sw_readwrite8(struct comedi_device *dev,
because it is a per-subdevice field, and serial is
a separate subdevice from DIO. */
devpriv->dio_output &= ~DIO_SDOUT;
- if (data_out & mask) {
+ if (data_out & mask)
devpriv->dio_output |= DIO_SDOUT;
- }
devpriv->stc_writew(dev, devpriv->dio_output,
DIO_Output_Register);
@@ -4003,15 +3840,12 @@ static int ni_serial_sw_readwrite8(struct comedi_device *dev,
/* Input current bit */
if (devpriv->stc_readw(dev,
- DIO_Parallel_Input_Register) & DIO_SDIN)
- {
-/* printk("DIO_P_I_R: 0x%x\n", devpriv->stc_readw(dev, DIO_Parallel_Input_Register)); */
+ DIO_Parallel_Input_Register) & DIO_SDIN) {
+ /* printk("DIO_P_I_R: 0x%x\n", devpriv->stc_readw(dev, DIO_Parallel_Input_Register)); */
input |= mask;
}
}
-#ifdef DEBUG_DIO
- printk("ni_serial_sw_readwrite8: inputted 0x%x\n", input);
-#endif
+
if (data_in)
*data_in = input;
@@ -4023,9 +3857,8 @@ static void mio_common_detach(struct comedi_device *dev)
struct ni_private *devpriv = dev->private;
if (devpriv) {
- if (devpriv->counter_dev) {
+ if (devpriv->counter_dev)
ni_gpct_device_destroy(devpriv->counter_dev);
- }
}
}
@@ -4044,82 +3877,82 @@ static unsigned ni_gpct_to_stc_register(enum ni_gpct_register reg)
{
unsigned stc_register;
switch (reg) {
- case NITIO_G0_Autoincrement_Reg:
+ case NITIO_G0_AUTO_INC:
stc_register = G_Autoincrement_Register(0);
break;
- case NITIO_G1_Autoincrement_Reg:
+ case NITIO_G1_AUTO_INC:
stc_register = G_Autoincrement_Register(1);
break;
- case NITIO_G0_Command_Reg:
+ case NITIO_G0_CMD:
stc_register = G_Command_Register(0);
break;
- case NITIO_G1_Command_Reg:
+ case NITIO_G1_CMD:
stc_register = G_Command_Register(1);
break;
- case NITIO_G0_HW_Save_Reg:
+ case NITIO_G0_HW_SAVE:
stc_register = G_HW_Save_Register(0);
break;
- case NITIO_G1_HW_Save_Reg:
+ case NITIO_G1_HW_SAVE:
stc_register = G_HW_Save_Register(1);
break;
- case NITIO_G0_SW_Save_Reg:
+ case NITIO_G0_SW_SAVE:
stc_register = G_Save_Register(0);
break;
- case NITIO_G1_SW_Save_Reg:
+ case NITIO_G1_SW_SAVE:
stc_register = G_Save_Register(1);
break;
- case NITIO_G0_Mode_Reg:
+ case NITIO_G0_MODE:
stc_register = G_Mode_Register(0);
break;
- case NITIO_G1_Mode_Reg:
+ case NITIO_G1_MODE:
stc_register = G_Mode_Register(1);
break;
- case NITIO_G0_LoadA_Reg:
+ case NITIO_G0_LOADA:
stc_register = G_Load_A_Register(0);
break;
- case NITIO_G1_LoadA_Reg:
+ case NITIO_G1_LOADA:
stc_register = G_Load_A_Register(1);
break;
- case NITIO_G0_LoadB_Reg:
+ case NITIO_G0_LOADB:
stc_register = G_Load_B_Register(0);
break;
- case NITIO_G1_LoadB_Reg:
+ case NITIO_G1_LOADB:
stc_register = G_Load_B_Register(1);
break;
- case NITIO_G0_Input_Select_Reg:
+ case NITIO_G0_INPUT_SEL:
stc_register = G_Input_Select_Register(0);
break;
- case NITIO_G1_Input_Select_Reg:
+ case NITIO_G1_INPUT_SEL:
stc_register = G_Input_Select_Register(1);
break;
- case NITIO_G01_Status_Reg:
+ case NITIO_G01_STATUS:
stc_register = G_Status_Register;
break;
- case NITIO_G01_Joint_Reset_Reg:
+ case NITIO_G01_RESET:
stc_register = Joint_Reset_Register;
break;
- case NITIO_G01_Joint_Status1_Reg:
+ case NITIO_G01_STATUS1:
stc_register = Joint_Status_1_Register;
break;
- case NITIO_G01_Joint_Status2_Reg:
+ case NITIO_G01_STATUS2:
stc_register = Joint_Status_2_Register;
break;
- case NITIO_G0_Interrupt_Acknowledge_Reg:
+ case NITIO_G0_INT_ACK:
stc_register = Interrupt_A_Ack_Register;
break;
- case NITIO_G1_Interrupt_Acknowledge_Reg:
+ case NITIO_G1_INT_ACK:
stc_register = Interrupt_B_Ack_Register;
break;
- case NITIO_G0_Status_Reg:
+ case NITIO_G0_STATUS:
stc_register = AI_Status_1_Register;
break;
- case NITIO_G1_Status_Reg:
+ case NITIO_G1_STATUS:
stc_register = AO_Status_1_Register;
break;
- case NITIO_G0_Interrupt_Enable_Reg:
+ case NITIO_G0_INT_ENA:
stc_register = Interrupt_A_Enable_Register;
break;
- case NITIO_G1_Interrupt_Enable_Reg:
+ case NITIO_G1_INT_ENA:
stc_register = Interrupt_B_Enable_Register;
break;
default:
@@ -4147,52 +3980,52 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits,
switch (reg) {
/* m-series-only registers */
- case NITIO_G0_Counting_Mode_Reg:
+ case NITIO_G0_CNT_MODE:
ni_writew(bits, M_Offset_G0_Counting_Mode);
break;
- case NITIO_G1_Counting_Mode_Reg:
+ case NITIO_G1_CNT_MODE:
ni_writew(bits, M_Offset_G1_Counting_Mode);
break;
- case NITIO_G0_Second_Gate_Reg:
+ case NITIO_G0_GATE2:
ni_writew(bits, M_Offset_G0_Second_Gate);
break;
- case NITIO_G1_Second_Gate_Reg:
+ case NITIO_G1_GATE2:
ni_writew(bits, M_Offset_G1_Second_Gate);
break;
- case NITIO_G0_DMA_Config_Reg:
+ case NITIO_G0_DMA_CFG:
ni_writew(bits, M_Offset_G0_DMA_Config);
break;
- case NITIO_G1_DMA_Config_Reg:
+ case NITIO_G1_DMA_CFG:
ni_writew(bits, M_Offset_G1_DMA_Config);
break;
- case NITIO_G0_ABZ_Reg:
+ case NITIO_G0_ABZ:
ni_writew(bits, M_Offset_G0_MSeries_ABZ);
break;
- case NITIO_G1_ABZ_Reg:
+ case NITIO_G1_ABZ:
ni_writew(bits, M_Offset_G1_MSeries_ABZ);
break;
/* 32 bit registers */
- case NITIO_G0_LoadA_Reg:
- case NITIO_G1_LoadA_Reg:
- case NITIO_G0_LoadB_Reg:
- case NITIO_G1_LoadB_Reg:
+ case NITIO_G0_LOADA:
+ case NITIO_G1_LOADA:
+ case NITIO_G0_LOADB:
+ case NITIO_G1_LOADB:
stc_register = ni_gpct_to_stc_register(reg);
devpriv->stc_writel(dev, bits, stc_register);
break;
/* 16 bit registers */
- case NITIO_G0_Interrupt_Enable_Reg:
+ case NITIO_G0_INT_ENA:
BUG_ON(bits & ~gpct_interrupt_a_enable_mask);
ni_set_bitfield(dev, Interrupt_A_Enable_Register,
gpct_interrupt_a_enable_mask, bits);
break;
- case NITIO_G1_Interrupt_Enable_Reg:
+ case NITIO_G1_INT_ENA:
BUG_ON(bits & ~gpct_interrupt_b_enable_mask);
ni_set_bitfield(dev, Interrupt_B_Enable_Register,
gpct_interrupt_b_enable_mask, bits);
break;
- case NITIO_G01_Joint_Reset_Reg:
+ case NITIO_G01_RESET:
BUG_ON(bits & ~gpct_joint_reset_mask);
/* fall-through */
default:
@@ -4210,21 +4043,18 @@ static unsigned ni_gpct_read_register(struct ni_gpct *counter,
switch (reg) {
/* m-series only registers */
- case NITIO_G0_DMA_Status_Reg:
+ case NITIO_G0_DMA_STATUS:
return ni_readw(M_Offset_G0_DMA_Status);
- break;
- case NITIO_G1_DMA_Status_Reg:
+ case NITIO_G1_DMA_STATUS:
return ni_readw(M_Offset_G1_DMA_Status);
- break;
/* 32 bit registers */
- case NITIO_G0_HW_Save_Reg:
- case NITIO_G1_HW_Save_Reg:
- case NITIO_G0_SW_Save_Reg:
- case NITIO_G1_SW_Save_Reg:
+ case NITIO_G0_HW_SAVE:
+ case NITIO_G1_HW_SAVE:
+ case NITIO_G0_SW_SAVE:
+ case NITIO_G1_SW_SAVE:
stc_register = ni_gpct_to_stc_register(reg);
return devpriv->stc_readl(dev, stc_register);
- break;
/* 16 bit registers */
default:
@@ -4391,11 +4221,10 @@ static int ni_E_init(struct comedi_device *dev)
s->maxdata = (1 << board->aobits) - 1;
s->range_table = board->ao_range_table;
s->insn_read = &ni_ao_insn_read;
- if (board->reg_type & ni_reg_6xxx_mask) {
+ if (board->reg_type & ni_reg_6xxx_mask)
s->insn_write = &ni_ao_insn_write_671x;
- } else {
+ else
s->insn_write = &ni_ao_insn_write;
- }
s->insn_config = &ni_ao_insn_config;
#ifdef PCIDMA
if (board->n_aochan) {
@@ -4429,7 +4258,7 @@ static int ni_E_init(struct comedi_device *dev)
s->n_chan = board->num_p0_dio_channels;
if (board->reg_type & ni_reg_m_series_mask) {
s->subdev_flags |=
- SDF_LSAMPL | SDF_CMD_WRITE /* | SDF_CMD_READ */ ;
+ SDF_LSAMPL | SDF_CMD_WRITE /* | SDF_CMD_READ */;
s->insn_bits = &ni_m_series_dio_insn_bits;
s->insn_config = &ni_m_series_dio_insn_config;
s->do_cmd = &ni_cdio_cmd;
@@ -4450,7 +4279,10 @@ static int ni_E_init(struct comedi_device *dev)
/* 8255 device */
s = &dev->subdevices[NI_8255_DIO_SUBDEV];
if (board->has_8255) {
- subdev_8255_init(dev, s, ni_8255_callback, (unsigned long)dev);
+ ret = subdev_8255_init(dev, s, ni_8255_callback,
+ (unsigned long)dev);
+ if (ret)
+ return ret;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -4511,9 +4343,8 @@ static int ni_E_init(struct comedi_device *dev)
s->n_chan = 10;
}
s->maxdata = 1;
- if (board->reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask)
s->insn_bits = &ni_pfi_insn_bits;
- }
s->insn_config = &ni_pfi_insn_config;
ni_set_bits(dev, IO_Bidirection_Pin_Register, ~0, 0);
@@ -4553,16 +4384,18 @@ static int ni_E_init(struct comedi_device *dev)
s->insn_config = ni_rtsi_insn_config;
ni_rtsi_init(dev);
- if (board->reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask)
counter_variant = ni_gpct_variant_m_series;
- } else {
+ else
counter_variant = ni_gpct_variant_e_series;
- }
devpriv->counter_dev = ni_gpct_device_construct(dev,
&ni_gpct_write_register,
&ni_gpct_read_register,
counter_variant,
NUM_GPCT);
+ if (!devpriv->counter_dev)
+ return -ENOMEM;
+
/* General purpose counters */
for (j = 0; j < NUM_GPCT; ++j) {
s = &dev->subdevices[NI_GPCT_SUBDEV(j)];
@@ -4573,14 +4406,14 @@ static int ni_E_init(struct comedi_device *dev)
s->maxdata = 0xffffffff;
else
s->maxdata = 0xffffff;
- s->insn_read = &ni_gpct_insn_read;
- s->insn_write = &ni_gpct_insn_write;
- s->insn_config = &ni_gpct_insn_config;
+ s->insn_read = ni_tio_insn_read;
+ s->insn_write = ni_tio_insn_read;
+ s->insn_config = ni_tio_insn_config;
#ifdef PCIDMA
s->subdev_flags |= SDF_CMD_READ /* | SDF_CMD_WRITE */;
s->do_cmd = &ni_gpct_cmd;
s->len_chanlist = 1;
- s->do_cmdtest = &ni_gpct_cmdtest;
+ s->do_cmdtest = ni_tio_cmdtest;
s->cancel = &ni_gpct_cancel;
s->async_dma_dir = DMA_BIDIRECTIONAL;
#endif
@@ -4653,7 +4486,6 @@ static int ni_E_init(struct comedi_device *dev)
ni_writeb(0x0, M_Offset_AO_Calibration);
}
- printk("\n");
return 0;
}
@@ -4901,7 +4733,7 @@ static int pack_ad8842(int addr, int val, int *bitstring);
struct caldac_struct {
int n_chans;
int n_bits;
- int (*packbits) (int, int, int *);
+ int (*packbits)(int, int, int *);
};
static struct caldac_struct caldacs[] = {
@@ -4944,9 +4776,8 @@ static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s)
if (diffbits) {
unsigned int *maxdata_list;
- if (n_chans > MAX_N_CALDACS) {
+ if (n_chans > MAX_N_CALDACS)
printk("BUG! MAX_N_CALDACS too small\n");
- }
s->maxdata_list = maxdata_list = devpriv->caldac_maxdata_list;
chan = 0;
for (i = 0; i < n_dacs; i++) {
@@ -5143,36 +4974,11 @@ static void GPCT_Reset(struct comedi_device *dev, int chan)
#endif
-static int ni_gpct_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct ni_gpct *counter = s->private;
- return ni_tio_insn_config(counter, insn, data);
-}
-
-static int ni_gpct_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct ni_gpct *counter = s->private;
- return ni_tio_rinsn(counter, insn, data);
-}
-
-static int ni_gpct_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct ni_gpct *counter = s->private;
- return ni_tio_winsn(counter, insn, data);
-}
-
#ifdef PCIDMA
static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
- int retval;
struct ni_gpct *counter = s->private;
-/* const struct comedi_cmd *cmd = &s->async->cmd; */
+ int retval;
retval = ni_request_gpct_mite_channel(dev, counter->counter_index,
COMEDI_INPUT);
@@ -5183,25 +4989,14 @@ static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL, NULL);
ni_e_series_enable_second_irq(dev, counter->counter_index, 1);
- retval = ni_tio_cmd(counter, s->async);
- return retval;
-}
-#endif
-
-#ifdef PCIDMA
-static int ni_gpct_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd)
-{
- struct ni_gpct *counter = s->private;
- return ni_tio_cmdtest(counter, cmd);
- return -ENOTSUPP;
+ return ni_tio_cmd(dev, s);
}
#endif
+#ifdef PCIDMA
static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
-#ifdef PCIDMA
struct ni_gpct *counter = s->private;
int retval;
@@ -5209,10 +5004,8 @@ static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
ni_e_series_enable_second_irq(dev, counter->counter_index, 0);
ni_release_gpct_mite_channel(dev, counter->counter_index);
return retval;
-#else
- return 0;
-#endif
}
+#endif
/*
*
@@ -5330,9 +5123,8 @@ static int ni_config_filter(struct comedi_device *dev, unsigned pfi_channel,
struct ni_private *devpriv __maybe_unused = dev->private;
unsigned bits;
- if ((board->reg_type & ni_reg_m_series_mask) == 0) {
+ if ((board->reg_type & ni_reg_m_series_mask) == 0)
return -ENOTSUPP;
- }
bits = ni_readl(M_Offset_PFI_Filter);
bits &= ~MSeries_PFI_Filter_Select_Mask(pfi_channel);
bits |= MSeries_PFI_Filter_Select_Bits(pfi_channel, filter);
@@ -5413,9 +5205,8 @@ static void ni_rtsi_init(struct comedi_device *dev)
/* Set clock mode to internal */
devpriv->clock_and_fout2 = MSeries_RTSI_10MHz_Bit;
- if (ni_set_master_clock(dev, NI_MIO_INTERNAL_CLOCK, 0) < 0) {
+ if (ni_set_master_clock(dev, NI_MIO_INTERNAL_CLOCK, 0) < 0)
printk("ni_set_master_clock failed, bug?");
- }
/* default internal lines routing to RTSI bus lines */
devpriv->rtsi_trig_a_output_reg =
RTSI_Trig_Output_Bits(0,
@@ -5598,9 +5389,8 @@ static int ni_mseries_set_pll_master_clock(struct comedi_device *dev,
devpriv->clock_source = source;
/* it seems to typically take a few hundred microseconds for PLL to lock */
for (i = 0; i < timeout; ++i) {
- if (ni_readw(M_Offset_PLL_Status) & MSeries_PLL_Locked_Bit) {
+ if (ni_readw(M_Offset_PLL_Status) & MSeries_PLL_Locked_Bit)
break;
- }
udelay(1);
}
if (i == timeout) {
@@ -5822,13 +5612,11 @@ static int cs5529_wait_for_idle(struct comedi_device *dev)
for (i = 0; i < timeout; i++) {
status = ni_ao_win_inw(dev, CAL_ADC_Status_67xx);
- if ((status & CSS_ADC_BUSY) == 0) {
+ if ((status & CSS_ADC_BUSY) == 0)
break;
- }
set_current_state(TASK_INTERRUPTIBLE);
- if (schedule_timeout(1)) {
+ if (schedule_timeout(1))
return -EIO;
- }
}
/* printk("looped %i times waiting for idle\n", i); */
if (i == timeout) {
@@ -5854,9 +5642,8 @@ static void cs5529_command(struct comedi_device *dev, unsigned short value)
udelay(1);
}
/* printk("looped %i times writing command to cs5529\n", i); */
- if (i == timeout) {
+ if (i == timeout)
comedi_error(dev, "possible problem - never saw adc go busy?");
- }
}
/* write to cs5529 register */
@@ -5873,25 +5660,6 @@ static void cs5529_config_write(struct comedi_device *dev, unsigned int value,
comedi_error(dev, "time or signal in cs5529_config_write()");
}
-#ifdef NI_CS5529_DEBUG
-/* read from cs5529 register */
-static unsigned int cs5529_config_read(struct comedi_device *dev,
- unsigned int reg_select_bits)
-{
- unsigned int value;
-
- reg_select_bits &= CSCMD_REGISTER_SELECT_MASK;
- cs5529_command(dev, CSCMD_COMMAND | CSCMD_READ | reg_select_bits);
- if (cs5529_wait_for_idle(dev))
- comedi_error(dev, "timeout or signal in cs5529_config_read()");
- value = (ni_ao_win_inw(dev,
- CAL_ADC_Config_Data_High_Word_67xx) << 16) &
- 0xff0000;
- value |= ni_ao_win_inw(dev, CAL_ADC_Config_Data_Low_Word_67xx) & 0xffff;
- return value;
-}
-#endif
-
static int cs5529_do_conversion(struct comedi_device *dev, unsigned short *data)
{
int retval;
@@ -5968,12 +5736,5 @@ static int init_cs5529(struct comedi_device *dev)
if (cs5529_wait_for_idle(dev))
comedi_error(dev, "timeout or signal in init_cs5529()\n");
#endif
-#ifdef NI_CS5529_DEBUG
- printk("config: 0x%x\n", cs5529_config_read(dev,
- CSCMD_CONFIG_REGISTER));
- printk("gain: 0x%x\n", cs5529_config_read(dev, CSCMD_GAIN_REGISTER));
- printk("offset: 0x%x\n", cs5529_config_read(dev,
- CSCMD_OFFSET_REGISTER));
-#endif
return 0;
}
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index 229a273f201..de421486b75 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -47,8 +47,6 @@ See the notes in the ni_atmio.o driver.
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
-#undef DEBUG
-
#define ATMIO 1
#undef PCIMIO
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index e3a8fa96d9b..5fc74d6ff6a 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -47,8 +47,6 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org
*/
#define USE_DMA
-/* #define DEBUG 1 */
-/* #define DEBUG_FLAGS */
#include <linux/module.h>
#include <linux/delay.h>
@@ -60,13 +58,6 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org
#include "comedi_fc.h"
#include "mite.h"
-#undef DPRINTK
-#ifdef DEBUG
-#define DPRINTK(format, args...) pr_debug(format, ## args)
-#else
-#define DPRINTK(format, args...) do { } while (0)
-#endif
-
#define PCI_DIO_SIZE 4096
#define PCI_MITE_SIZE 4096
@@ -272,9 +263,6 @@ enum FPGA_Control_Bits {
#define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC)
#endif
-static int ni_pcidio_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-
enum nidio_boardid {
BOARD_PCIDIO_32HS,
BOARD_PXI6533,
@@ -319,14 +307,6 @@ static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode);
static int setup_mite_dma(struct comedi_device *dev,
struct comedi_subdevice *s);
-#ifdef DEBUG_FLAGS
-static void ni_pcidio_print_flags(unsigned int flags);
-static void ni_pcidio_print_status(unsigned int status);
-#else
-#define ni_pcidio_print_flags(x)
-#define ni_pcidio_print_status(x)
-#endif
-
static int ni_pcidio_request_di_mite_channel(struct comedi_device *dev)
{
struct nidio96_private *devpriv = dev->private;
@@ -370,17 +350,6 @@ static void ni_pcidio_release_di_mite_channel(struct comedi_device *dev)
spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
}
-static void ni_pcidio_event(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- if (s->
- async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
- COMEDI_CB_OVERFLOW)) {
- ni_pcidio_cancel(dev, s);
- }
- comedi_event(dev, s);
-}
-
static int ni_pcidio_poll(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct nidio96_private *devpriv = dev->private;
@@ -390,7 +359,7 @@ static int ni_pcidio_poll(struct comedi_device *dev, struct comedi_subdevice *s)
spin_lock_irqsave(&dev->spinlock, irq_flags);
spin_lock(&devpriv->mite_channel_lock);
if (devpriv->di_mite_chan)
- mite_sync_input_dma(devpriv->di_mite_chan, s->async);
+ mite_sync_input_dma(devpriv->di_mite_chan, s);
spin_unlock(&devpriv->mite_channel_lock);
count = s->async->buf_write_count - s->async->buf_read_count;
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
@@ -401,7 +370,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct nidio96_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
+ struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async = s->async;
struct mite_struct *mite = devpriv->mite;
@@ -427,30 +396,22 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
Interrupt_And_Window_Status);
flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags);
- DPRINTK("ni_pcidio_interrupt: status=0x%02x,flags=0x%02x\n",
- status, flags);
- ni_pcidio_print_flags(flags);
- ni_pcidio_print_status(status);
-
spin_lock(&devpriv->mite_channel_lock);
if (devpriv->di_mite_chan)
m_status = mite_get_status(devpriv->di_mite_chan);
-#ifdef MITE_DEBUG
- mite_print_chsr(m_status);
-#endif
- /* mite_dump_regs(mite); */
if (m_status & CHSR_INT) {
if (m_status & CHSR_LINKC) {
writel(CHOR_CLRLC,
mite->mite_io_addr +
MITE_CHOR(devpriv->di_mite_chan->channel));
- mite_sync_input_dma(devpriv->di_mite_chan, s->async);
+ mite_sync_input_dma(devpriv->di_mite_chan, s);
/* XXX need to byteswap */
}
if (m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_DRDY |
CHSR_DRQ1 | CHSR_MRDY)) {
- DPRINTK("unknown mite interrupt, disabling IRQ\n");
+ dev_dbg(dev->class_dev,
+ "unknown mite interrupt, disabling IRQ\n");
async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
disable_irq(dev->irq);
}
@@ -460,7 +421,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
while (status & DataLeft) {
work++;
if (work > 20) {
- DPRINTK("too much work in interrupt\n");
+ dev_dbg(dev->class_dev, "too much work in interrupt\n");
writeb(0x00,
devpriv->mite->daq_io_addr +
Master_DMA_And_Interrupt_Control);
@@ -470,11 +431,11 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
flags &= IntEn;
if (flags & TransferReady) {
- /* DPRINTK("TransferReady\n"); */
while (flags & TransferReady) {
work++;
if (work > 100) {
- DPRINTK("too much work in interrupt\n");
+ dev_dbg(dev->class_dev,
+ "too much work in interrupt\n");
writeb(0x00,
devpriv->mite->daq_io_addr +
Master_DMA_And_Interrupt_Control
@@ -486,23 +447,15 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
Group_1_FIFO);
data1 = auxdata & 0xffff;
data2 = (auxdata & 0xffff0000) >> 16;
- comedi_buf_put(async, data1);
- comedi_buf_put(async, data2);
- /* DPRINTK("read:%d, %d\n",data1,data2); */
+ comedi_buf_put(s, data1);
+ comedi_buf_put(s, data2);
flags = readb(devpriv->mite->daq_io_addr +
Group_1_Flags);
}
- /* DPRINTK("buf_int_count: %d\n",
- async->buf_int_count); */
- /* DPRINTK("1) IntEn=%d,flags=%d,status=%d\n",
- IntEn,flags,status); */
- /* ni_pcidio_print_flags(flags); */
- /* ni_pcidio_print_status(status); */
async->events |= COMEDI_CB_BLOCK;
}
if (flags & CountExpired) {
- DPRINTK("CountExpired\n");
writeb(ClearExpired,
devpriv->mite->daq_io_addr +
Group_1_Second_Clear);
@@ -511,45 +464,30 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
writeb(0x00, devpriv->mite->daq_io_addr + OpMode);
break;
} else if (flags & Waited) {
- DPRINTK("Waited\n");
writeb(ClearWaited,
devpriv->mite->daq_io_addr +
Group_1_First_Clear);
async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
break;
} else if (flags & PrimaryTC) {
- DPRINTK("PrimaryTC\n");
writeb(ClearPrimaryTC,
devpriv->mite->daq_io_addr +
Group_1_First_Clear);
async->events |= COMEDI_CB_EOA;
} else if (flags & SecondaryTC) {
- DPRINTK("SecondaryTC\n");
writeb(ClearSecondaryTC,
devpriv->mite->daq_io_addr +
Group_1_First_Clear);
async->events |= COMEDI_CB_EOA;
}
-#if 0
- else {
- DPRINTK("ni_pcidio: unknown interrupt\n");
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- writeb(0x00,
- devpriv->mite->daq_io_addr +
- Master_DMA_And_Interrupt_Control);
- }
-#endif
+
flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags);
status = readb(devpriv->mite->daq_io_addr +
Interrupt_And_Window_Status);
- /* DPRINTK("loop end: IntEn=0x%02x,flags=0x%02x,"
- "status=0x%02x\n", IntEn, flags, status); */
- /* ni_pcidio_print_flags(flags); */
- /* ni_pcidio_print_status(status); */
}
out:
- ni_pcidio_event(dev, s);
+ cfc_handle_events(dev, s);
#if 0
if (!tag) {
writeb(0x03,
@@ -562,82 +500,6 @@ out:
return IRQ_HANDLED;
}
-#ifdef DEBUG_FLAGS
-static const char *bit_set_string(unsigned int bits, unsigned int bit,
- const char *const strings[])
-{
- return (bits & (1U << bit)) ? strings[bit] : "";
-}
-
-static const char *const flags_strings[] = {
- " TransferReady", " CountExpired", " 2", " 3",
- " 4", " Waited", " PrimaryTC", " SecondaryTC",
-};
-
-
-static void ni_pcidio_print_flags(unsigned int flags)
-{
- pr_debug("group_1_flags:%s%s%s%s%s%s%s%s\n",
- bit_set_string(flags, 7, flags_strings),
- bit_set_string(flags, 6, flags_strings),
- bit_set_string(flags, 5, flags_strings),
- bit_set_string(flags, 4, flags_strings),
- bit_set_string(flags, 3, flags_strings),
- bit_set_string(flags, 2, flags_strings),
- bit_set_string(flags, 1, flags_strings),
- bit_set_string(flags, 0, flags_strings));
-}
-
-static const char *const status_strings[] = {
- " DataLeft1", " Reserved1", " Req1", " StopTrig1",
- " DataLeft2", " Reserved2", " Req2", " StopTrig2",
-};
-
-static void ni_pcidio_print_status(unsigned int flags)
-{
- pr_debug("group_status:%s%s%s%s%s%s%s%s\n",
- bit_set_string(flags, 7, status_strings),
- bit_set_string(flags, 6, status_strings),
- bit_set_string(flags, 5, status_strings),
- bit_set_string(flags, 4, status_strings),
- bit_set_string(flags, 3, status_strings),
- bit_set_string(flags, 2, status_strings),
- bit_set_string(flags, 1, status_strings),
- bit_set_string(flags, 0, status_strings));
-}
-#endif
-
-#ifdef unused
-static void debug_int(struct comedi_device *dev)
-{
- struct nidio96_private *devpriv = dev->private;
- int a, b;
- static int n_int;
- struct timeval tv;
-
- do_gettimeofday(&tv);
- a = readb(devpriv->mite->daq_io_addr + Group_Status);
- b = readb(devpriv->mite->daq_io_addr + Group_1_Flags);
-
- if (n_int < 10) {
- DPRINTK("status 0x%02x flags 0x%02x time %06d\n", a, b,
- (int)tv.tv_usec);
- }
-
- while (b & 1) {
- writew(0xff, devpriv->mite->daq_io_addr + Group_1_FIFO);
- b = readb(devpriv->mite->daq_io_addr + Group_1_Flags);
- }
-
- b = readb(devpriv->mite->daq_io_addr + Group_1_Flags);
-
- if (n_int < 10) {
- DPRINTK("new status 0x%02x\n", b);
- n_int++;
- }
-}
-#endif
-
static int ni_pcidio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -674,7 +536,7 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
int err = 0;
- int tmp;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -733,11 +595,9 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
- ni_pcidio_ns_to_timer(&cmd->scan_begin_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->scan_begin_arg)
- err++;
+ arg = cmd->scan_begin_arg;
+ ni_pcidio_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
if (err)
@@ -883,7 +743,6 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
s->async->inttrig = ni_pcidio_inttrig;
}
- DPRINTK("ni_pcidio: command started\n");
return 0;
}
@@ -898,7 +757,7 @@ static int setup_mite_dma(struct comedi_device *dev, struct comedi_subdevice *s)
return retval;
/* write alloc the entire buffer */
- comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
+ comedi_buf_write_alloc(s, s->async->prealloc_bufsz);
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
if (devpriv->di_mite_chan) {
@@ -912,11 +771,13 @@ static int setup_mite_dma(struct comedi_device *dev, struct comedi_subdevice *s)
}
static int ni_pcidio_inttrig(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int trignum)
+ struct comedi_subdevice *s,
+ unsigned int trig_num)
{
struct nidio96_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
- if (trignum != 0)
+ if (trig_num != cmd->start_arg)
return -EINVAL;
writeb(devpriv->OpModeBits, devpriv->mite->daq_io_addr + OpMode);
@@ -943,7 +804,7 @@ static int ni_pcidio_change(struct comedi_device *dev,
struct nidio96_private *devpriv = dev->private;
int ret;
- ret = mite_buf_change(devpriv->di_mite_ring, s->async);
+ ret = mite_buf_change(devpriv->di_mite_ring, s);
if (ret < 0)
return ret;
@@ -1074,6 +935,19 @@ static int pci_6534_upload_firmware(struct comedi_device *dev)
return ret;
}
+static void nidio_reset_board(struct comedi_device *dev)
+{
+ struct nidio96_private *devpriv = dev->private;
+ void __iomem *daq_mmio = devpriv->mite->daq_io_addr;
+
+ writel(0, daq_mmio + Port_IO(0));
+ writel(0, daq_mmio + Port_Pin_Directions(0));
+ writel(0, daq_mmio + Port_Pin_Mask(0));
+
+ /* disable interrupts on board */
+ writeb(0, daq_mmio + Master_DMA_And_Interrupt_Control);
+}
+
static int nidio_auto_attach(struct comedi_device *dev,
unsigned long context)
{
@@ -1115,13 +989,14 @@ static int nidio_auto_attach(struct comedi_device *dev,
if (devpriv->di_mite_ring == NULL)
return -ENOMEM;
- irq = mite_irq(devpriv->mite);
if (board->uses_firmware) {
ret = pci_6534_upload_firmware(dev);
if (ret < 0)
return ret;
}
+ nidio_reset_board(dev);
+
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
return ret;
@@ -1149,21 +1024,13 @@ static int nidio_auto_attach(struct comedi_device *dev,
s->async_dma_dir = DMA_BIDIRECTIONAL;
s->poll = &ni_pcidio_poll;
- writel(0, devpriv->mite->daq_io_addr + Port_IO(0));
- writel(0, devpriv->mite->daq_io_addr + Port_Pin_Directions(0));
- writel(0, devpriv->mite->daq_io_addr + Port_Pin_Mask(0));
-
- /* disable interrupts on board */
- writeb(0x00,
- devpriv->mite->daq_io_addr +
- Master_DMA_And_Interrupt_Control);
-
- ret = request_irq(irq, nidio_interrupt, IRQF_SHARED,
- "ni_pcidio", dev);
- if (ret < 0)
- dev_warn(dev->class_dev, "irq not available\n");
-
- dev->irq = irq;
+ irq = mite_irq(devpriv->mite);
+ if (irq) {
+ ret = request_irq(irq, nidio_interrupt, IRQF_SHARED,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = irq;
+ }
return 0;
}
@@ -1200,7 +1067,7 @@ static int ni_pcidio_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &ni_pcidio_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = {
+static const struct pci_device_id ni_pcidio_pci_table[] = {
{ PCI_VDEVICE(NI, 0x1150), BOARD_PCIDIO_32HS },
{ PCI_VDEVICE(NI, 0x12b0), BOARD_PCI6534 },
{ PCI_VDEVICE(NI, 0x1320), BOARD_PXI6533 },
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 536be83af54..89300dc78e3 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -116,8 +116,6 @@ Bugs:
#include "ni_stc.h"
#include "mite.h"
-/* #define PCI_DEBUG */
-
#define PCIDMA
#define PCIMIO 1
@@ -134,24 +132,26 @@ Bugs:
63 different possibilities. An AO channel
can not act as it's own OFFSET or REFERENCE.
*/
-static const struct comedi_lrange range_ni_M_628x_ao = { 8, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE(-2, 2),
- RANGE(-1, 1),
- RANGE(-5, 15),
- RANGE(0, 10),
- RANGE(3, 7),
- RANGE(4, 6),
- RANGE_ext(-1, 1)
- }
+static const struct comedi_lrange range_ni_M_628x_ao = {
+ 8, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2),
+ BIP_RANGE(1),
+ RANGE(-5, 15),
+ UNI_RANGE(10),
+ RANGE(3, 7),
+ RANGE(4, 6),
+ RANGE_ext(-1, 1)
+ }
};
-static const struct comedi_lrange range_ni_M_625x_ao = { 3, {
- RANGE(-10, 10),
- RANGE(-5, 5),
- RANGE_ext(-1, 1)
- }
+static const struct comedi_lrange range_ni_M_625x_ao = {
+ 3, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ RANGE_ext(-1, 1)
+ }
};
enum ni_pcimio_boardid {
@@ -1178,9 +1178,9 @@ static void m_series_stc_writew(struct comedi_device *dev, uint16_t data,
offset = M_Offset_AO_FIFO_Clear;
break;
case DIO_Control_Register:
- printk
- ("%s: FIXME: register 0x%x does not map cleanly on to m-series boards.\n",
- __func__, reg);
+ dev_dbg(dev->class_dev,
+ "%s: FIXME: register 0x%x does not map cleanly on to m-series boards.\n",
+ __func__, reg);
return;
break;
case G_Autoincrement_Register(0):
@@ -1471,6 +1471,7 @@ static int pcimio_auto_attach(struct comedi_device *dev,
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
const struct ni_board_struct *board = NULL;
struct ni_private *devpriv;
+ unsigned int irq;
int ret;
if (context < ARRAY_SIZE(ni_boards))
@@ -1532,18 +1533,12 @@ static int pcimio_auto_attach(struct comedi_device *dev,
if (board->reg_type == ni_reg_6143)
init_6143(dev);
- dev->irq = mite_irq(devpriv->mite);
-
- if (dev->irq == 0) {
- pr_warn("unknown irq (bad)\n");
- } else {
- pr_debug("( irq = %u )\n", dev->irq);
- ret = request_irq(dev->irq, ni_E_interrupt, NI_E_IRQ_FLAGS,
- DRV_NAME, dev);
- if (ret < 0) {
- pr_warn("irq not available\n");
- dev->irq = 0;
- }
+ irq = mite_irq(devpriv->mite);
+ if (irq) {
+ ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = irq;
}
ret = ni_E_init(dev);
@@ -1556,7 +1551,7 @@ static int pcimio_auto_attach(struct comedi_device *dev,
dev->subdevices[NI_GPCT_SUBDEV(1)].buf_change = &pcimio_gpct1_change;
dev->subdevices[NI_DIO_SUBDEV].buf_change = &pcimio_dio_change;
- return ret;
+ return 0;
}
static int pcimio_ai_change(struct comedi_device *dev,
@@ -1565,7 +1560,7 @@ static int pcimio_ai_change(struct comedi_device *dev,
struct ni_private *devpriv = dev->private;
int ret;
- ret = mite_buf_change(devpriv->ai_mite_ring, s->async);
+ ret = mite_buf_change(devpriv->ai_mite_ring, s);
if (ret < 0)
return ret;
@@ -1578,7 +1573,7 @@ static int pcimio_ao_change(struct comedi_device *dev,
struct ni_private *devpriv = dev->private;
int ret;
- ret = mite_buf_change(devpriv->ao_mite_ring, s->async);
+ ret = mite_buf_change(devpriv->ao_mite_ring, s);
if (ret < 0)
return ret;
@@ -1592,7 +1587,7 @@ static int pcimio_gpct0_change(struct comedi_device *dev,
struct ni_private *devpriv = dev->private;
int ret;
- ret = mite_buf_change(devpriv->gpct_mite_ring[0], s->async);
+ ret = mite_buf_change(devpriv->gpct_mite_ring[0], s);
if (ret < 0)
return ret;
@@ -1606,7 +1601,7 @@ static int pcimio_gpct1_change(struct comedi_device *dev,
struct ni_private *devpriv = dev->private;
int ret;
- ret = mite_buf_change(devpriv->gpct_mite_ring[1], s->async);
+ ret = mite_buf_change(devpriv->gpct_mite_ring[1], s);
if (ret < 0)
return ret;
@@ -1619,7 +1614,7 @@ static int pcimio_dio_change(struct comedi_device *dev,
struct ni_private *devpriv = dev->private;
int ret;
- ret = mite_buf_change(devpriv->cdo_mite_ring, s->async);
+ ret = mite_buf_change(devpriv->cdo_mite_ring, s);
if (ret < 0)
return ret;
@@ -1639,7 +1634,7 @@ static int ni_pcimio_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &ni_pcimio_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(ni_pcimio_pci_table) = {
+static const struct pci_device_id ni_pcimio_pci_table[] = {
{ PCI_VDEVICE(NI, 0x0162), BOARD_PCIMIO_16XE_50 }, /* 0x1620? */
{ PCI_VDEVICE(NI, 0x1170), BOARD_PCIMIO_16XE_10 },
{ PCI_VDEVICE(NI, 0x1180), BOARD_PCIMIO_16E_1 },
diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c
index 9b120c77d83..92691b491c2 100644
--- a/drivers/staging/comedi/drivers/ni_tio.c
+++ b/drivers/staging/comedi/drivers/ni_tio.c
@@ -53,10 +53,6 @@ static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter,
unsigned generic_clock_source);
static unsigned ni_tio_generic_clock_src_select(const struct ni_gpct *counter);
-MODULE_AUTHOR("Comedi <comedi@comedi.org>");
-MODULE_DESCRIPTION("Comedi support for NI general-purpose counters");
-MODULE_LICENSE("GPL");
-
static inline enum Gi_Counting_Mode_Reg_Bits Gi_Alternate_Sync_Bit(enum
ni_gpct_variant
variant)
@@ -277,19 +273,6 @@ static inline unsigned NI_660x_RTSI_Second_Gate_Select(unsigned n)
static const unsigned int counter_status_mask =
COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING;
-static int __init ni_tio_init_module(void)
-{
- return 0;
-}
-
-module_init(ni_tio_init_module);
-
-static void __exit ni_tio_cleanup_module(void)
-{
-}
-
-module_exit(ni_tio_cleanup_module);
-
struct ni_gpct_device *ni_gpct_device_construct(struct comedi_device *dev,
void (*write_register) (struct
ni_gpct
@@ -362,74 +345,64 @@ static int ni_tio_second_gate_registers_present(const struct ni_gpct_device
static void ni_tio_reset_count_and_disarm(struct ni_gpct *counter)
{
- write_register(counter, Gi_Reset_Bit(counter->counter_index),
- NITIO_Gxx_Joint_Reset_Reg(counter->counter_index));
+ unsigned cidx = counter->counter_index;
+
+ write_register(counter, Gi_Reset_Bit(cidx), NITIO_RESET_REG(cidx));
}
void ni_tio_init_counter(struct ni_gpct *counter)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
+ unsigned cidx = counter->counter_index;
ni_tio_reset_count_and_disarm(counter);
+
/* initialize counter registers */
- counter_dev->regs[NITIO_Gi_Autoincrement_Reg(counter->counter_index)] =
- 0x0;
- write_register(counter,
- counter_dev->
- regs[NITIO_Gi_Autoincrement_Reg(counter->counter_index)],
- NITIO_Gi_Autoincrement_Reg(counter->counter_index));
- ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index),
+ counter_dev->regs[NITIO_AUTO_INC_REG(cidx)] = 0x0;
+ write_register(counter, counter_dev->regs[NITIO_AUTO_INC_REG(cidx)],
+ NITIO_AUTO_INC_REG(cidx));
+
+ ni_tio_set_bits(counter, NITIO_CMD_REG(cidx),
~0, Gi_Synchronize_Gate_Bit);
- ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index), ~0,
- 0);
- counter_dev->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] = 0x0;
- write_register(counter,
- counter_dev->
- regs[NITIO_Gi_LoadA_Reg(counter->counter_index)],
- NITIO_Gi_LoadA_Reg(counter->counter_index));
- counter_dev->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)] = 0x0;
- write_register(counter,
- counter_dev->
- regs[NITIO_Gi_LoadB_Reg(counter->counter_index)],
- NITIO_Gi_LoadB_Reg(counter->counter_index));
- ni_tio_set_bits(counter,
- NITIO_Gi_Input_Select_Reg(counter->counter_index), ~0,
- 0);
- if (ni_tio_counting_mode_registers_present(counter_dev)) {
- ni_tio_set_bits(counter,
- NITIO_Gi_Counting_Mode_Reg(counter->
- counter_index), ~0,
- 0);
- }
+
+ ni_tio_set_bits(counter, NITIO_MODE_REG(cidx), ~0, 0);
+
+ counter_dev->regs[NITIO_LOADA_REG(cidx)] = 0x0;
+ write_register(counter, counter_dev->regs[NITIO_LOADA_REG(cidx)],
+ NITIO_LOADA_REG(cidx));
+
+ counter_dev->regs[NITIO_LOADB_REG(cidx)] = 0x0;
+ write_register(counter, counter_dev->regs[NITIO_LOADB_REG(cidx)],
+ NITIO_LOADB_REG(cidx));
+
+ ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), ~0, 0);
+
+ if (ni_tio_counting_mode_registers_present(counter_dev))
+ ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx), ~0, 0);
+
if (ni_tio_second_gate_registers_present(counter_dev)) {
- counter_dev->
- regs[NITIO_Gi_Second_Gate_Reg(counter->counter_index)] =
- 0x0;
+ counter_dev->regs[NITIO_GATE2_REG(cidx)] = 0x0;
write_register(counter,
- counter_dev->
- regs[NITIO_Gi_Second_Gate_Reg
- (counter->counter_index)],
- NITIO_Gi_Second_Gate_Reg(counter->
- counter_index));
+ counter_dev->regs[NITIO_GATE2_REG(cidx)],
+ NITIO_GATE2_REG(cidx));
}
- ni_tio_set_bits(counter,
- NITIO_Gi_DMA_Config_Reg(counter->counter_index), ~0,
- 0x0);
- ni_tio_set_bits(counter,
- NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index),
- ~0, 0x0);
+
+ ni_tio_set_bits(counter, NITIO_DMA_CFG_REG(cidx), ~0, 0x0);
+
+ ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx), ~0, 0x0);
}
EXPORT_SYMBOL_GPL(ni_tio_init_counter);
static unsigned int ni_tio_counter_status(struct ni_gpct *counter)
{
- unsigned int status = 0;
+ unsigned cidx = counter->counter_index;
const unsigned bits = read_register(counter,
- NITIO_Gxx_Status_Reg(counter->
- counter_index));
- if (bits & Gi_Armed_Bit(counter->counter_index)) {
+ NITIO_SHARED_STATUS_REG(cidx));
+ unsigned int status = 0;
+
+ if (bits & Gi_Armed_Bit(cidx)) {
status |= COMEDI_COUNTER_ARMED;
- if (bits & Gi_Counting_Bit(counter->counter_index))
+ if (bits & Gi_Counting_Bit(cidx))
status |= COMEDI_COUNTER_COUNTING;
}
return status;
@@ -438,8 +411,8 @@ static unsigned int ni_tio_counter_status(struct ni_gpct *counter)
static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
- const unsigned counting_mode_reg =
- NITIO_Gi_Counting_Mode_Reg(counter->counter_index);
+ unsigned cidx = counter->counter_index;
+ const unsigned counting_mode_reg = NITIO_CNT_MODE_REG(cidx);
static const uint64_t min_normal_sync_period_ps = 25000;
const uint64_t clock_period_ps = ni_tio_clock_period_ps(counter,
ni_tio_generic_clock_src_select
@@ -476,6 +449,7 @@ static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync)
static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
+ unsigned cidx = counter->counter_index;
unsigned mode_reg_mask;
unsigned mode_reg_values;
unsigned input_select_bits = 0;
@@ -502,7 +476,7 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode)
default:
break;
}
- ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index),
+ ni_tio_set_bits(counter, NITIO_MODE_REG(cidx),
mode_reg_mask, mode_reg_values);
if (ni_tio_counting_mode_registers_present(counter_dev)) {
@@ -515,15 +489,13 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode)
Gi_Index_Phase_Bitshift) & Gi_Index_Phase_Mask;
if (mode & NI_GPCT_INDEX_ENABLE_BIT)
counting_mode_bits |= Gi_Index_Mode_Bit;
- ni_tio_set_bits(counter,
- NITIO_Gi_Counting_Mode_Reg(counter->
- counter_index),
+ ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx),
Gi_Counting_Mode_Mask | Gi_Index_Phase_Mask |
Gi_Index_Mode_Bit, counting_mode_bits);
ni_tio_set_sync_mode(counter, 0);
}
- ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index),
+ ni_tio_set_bits(counter, NITIO_CMD_REG(cidx),
Gi_Up_Down_Mask,
(mode >> NI_GPCT_COUNTING_DIRECTION_SHIFT) <<
Gi_Up_Down_Shift);
@@ -532,8 +504,7 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode)
input_select_bits |= Gi_Or_Gate_Bit;
if (mode & NI_GPCT_INVERT_OUTPUT_BIT)
input_select_bits |= Gi_Output_Polarity_Bit;
- ni_tio_set_bits(counter,
- NITIO_Gi_Input_Select_Reg(counter->counter_index),
+ ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx),
Gi_Gate_Select_Load_Source_Bit | Gi_Or_Gate_Bit |
Gi_Output_Polarity_Bit, input_select_bits);
@@ -543,7 +514,7 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode)
int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
-
+ unsigned cidx = counter->counter_index;
unsigned command_transient_bits = 0;
if (arm) {
@@ -581,9 +552,7 @@ int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger)
}
break;
}
- ni_tio_set_bits(counter,
- NITIO_Gi_Counting_Mode_Reg
- (counter->counter_index),
+ ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx),
Gi_HW_Arm_Select_Mask
(counter_dev->variant) |
Gi_HW_Arm_Enable_Bit,
@@ -592,8 +561,7 @@ int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger)
} else {
command_transient_bits |= Gi_Disarm_Bit;
}
- ni_tio_set_bits_transient(counter,
- NITIO_Gi_Command_Reg(counter->counter_index),
+ ni_tio_set_bits_transient(counter, NITIO_CMD_REG(cidx),
0, 0, command_transient_bits);
return 0;
}
@@ -717,8 +685,8 @@ static void ni_tio_set_source_subselect(struct ni_gpct *counter,
unsigned int clock_source)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
- const unsigned second_gate_reg =
- NITIO_Gi_Second_Gate_Reg(counter->counter_index);
+ unsigned cidx = counter->counter_index;
+ const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
if (counter_dev->variant != ni_gpct_variant_m_series)
return;
@@ -747,6 +715,7 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter,
unsigned int period_ns)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
+ unsigned cidx = counter->counter_index;
unsigned input_select_bits = 0;
static const uint64_t pico_per_nano = 1000;
@@ -766,8 +735,7 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter,
}
if (clock_source & NI_GPCT_INVERT_CLOCK_SRC_BIT)
input_select_bits |= Gi_Source_Polarity_Bit;
- ni_tio_set_bits(counter,
- NITIO_Gi_Input_Select_Reg(counter->counter_index),
+ ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx),
Gi_Source_Select_Mask | Gi_Source_Polarity_Bit,
input_select_bits);
ni_tio_set_source_subselect(counter, clock_source);
@@ -791,9 +759,7 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter,
return -EINVAL;
break;
}
- ni_tio_set_bits(counter,
- NITIO_Gi_Counting_Mode_Reg(counter->
- counter_index),
+ ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx),
Gi_Prescale_X2_Bit(counter_dev->variant) |
Gi_Prescale_X8_Bit(counter_dev->variant),
counting_mode_bits);
@@ -806,15 +772,12 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter,
static unsigned ni_tio_clock_src_modifiers(const struct ni_gpct *counter)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
- const unsigned counting_mode_bits = ni_tio_get_soft_copy(counter,
- NITIO_Gi_Counting_Mode_Reg
- (counter->
- counter_index));
+ unsigned cidx = counter->counter_index;
+ const unsigned counting_mode_bits =
+ ni_tio_get_soft_copy(counter, NITIO_CNT_MODE_REG(cidx));
unsigned bits = 0;
- if (ni_tio_get_soft_copy(counter,
- NITIO_Gi_Input_Select_Reg
- (counter->counter_index)) &
+ if (ni_tio_get_soft_copy(counter, NITIO_INPUT_SEL_REG(cidx)) &
Gi_Source_Polarity_Bit)
bits |= NI_GPCT_INVERT_CLOCK_SRC_BIT;
if (counting_mode_bits & Gi_Prescale_X2_Bit(counter_dev->variant))
@@ -827,15 +790,13 @@ static unsigned ni_tio_clock_src_modifiers(const struct ni_gpct *counter)
static unsigned ni_m_series_clock_src_select(const struct ni_gpct *counter)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
- const unsigned second_gate_reg =
- NITIO_Gi_Second_Gate_Reg(counter->counter_index);
+ unsigned cidx = counter->counter_index;
+ const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
unsigned clock_source = 0;
unsigned i;
- const unsigned input_select = (ni_tio_get_soft_copy(counter,
- NITIO_Gi_Input_Select_Reg
- (counter->counter_index))
- & Gi_Source_Select_Mask) >>
- Gi_Source_Select_Shift;
+ const unsigned input_select =
+ (ni_tio_get_soft_copy(counter, NITIO_INPUT_SEL_REG(cidx)) &
+ Gi_Source_Select_Mask) >> Gi_Source_Select_Shift;
switch (input_select) {
case NI_M_Series_Timebase_1_Clock:
@@ -895,12 +856,11 @@ static unsigned ni_m_series_clock_src_select(const struct ni_gpct *counter)
static unsigned ni_660x_clock_src_select(const struct ni_gpct *counter)
{
unsigned clock_source = 0;
+ unsigned cidx = counter->counter_index;
+ const unsigned input_select =
+ (ni_tio_get_soft_copy(counter, NITIO_INPUT_SEL_REG(cidx)) &
+ Gi_Source_Select_Mask) >> Gi_Source_Select_Shift;
unsigned i;
- const unsigned input_select = (ni_tio_get_soft_copy(counter,
- NITIO_Gi_Input_Select_Reg
- (counter->counter_index))
- & Gi_Source_Select_Mask) >>
- Gi_Source_Select_Shift;
switch (input_select) {
case NI_660x_Timebase_1_Clock:
@@ -1022,6 +982,7 @@ static void ni_tio_set_first_gate_modifiers(struct ni_gpct *counter,
unsigned int gate_source)
{
const unsigned mode_mask = Gi_Gate_Polarity_Bit | Gi_Gating_Mode_Mask;
+ unsigned cidx = counter->counter_index;
unsigned mode_values = 0;
if (gate_source & CR_INVERT)
@@ -1030,7 +991,7 @@ static void ni_tio_set_first_gate_modifiers(struct ni_gpct *counter,
mode_values |= Gi_Rising_Edge_Gating_Bits;
else
mode_values |= Gi_Level_Gating_Bits;
- ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index),
+ ni_tio_set_bits(counter, NITIO_MODE_REG(cidx),
mode_mask, mode_values);
}
@@ -1038,6 +999,7 @@ static int ni_660x_set_first_gate(struct ni_gpct *counter,
unsigned int gate_source)
{
const unsigned selected_gate = CR_CHAN(gate_source);
+ unsigned cidx = counter->counter_index;
/* bits of selected_gate that may be meaningful to input select register */
const unsigned selected_gate_mask = 0x1f;
unsigned ni_660x_gate_select;
@@ -1075,8 +1037,7 @@ static int ni_660x_set_first_gate(struct ni_gpct *counter,
return -EINVAL;
break;
}
- ni_tio_set_bits(counter,
- NITIO_Gi_Input_Select_Reg(counter->counter_index),
+ ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx),
Gi_Gate_Select_Mask,
Gi_Gate_Select_Bits(ni_660x_gate_select));
return 0;
@@ -1086,6 +1047,7 @@ static int ni_m_series_set_first_gate(struct ni_gpct *counter,
unsigned int gate_source)
{
const unsigned selected_gate = CR_CHAN(gate_source);
+ unsigned cidx = counter->counter_index;
/* bits of selected_gate that may be meaningful to input select register */
const unsigned selected_gate_mask = 0x1f;
unsigned ni_m_series_gate_select;
@@ -1124,8 +1086,7 @@ static int ni_m_series_set_first_gate(struct ni_gpct *counter,
return -EINVAL;
break;
}
- ni_tio_set_bits(counter,
- NITIO_Gi_Input_Select_Reg(counter->counter_index),
+ ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx),
Gi_Gate_Select_Mask,
Gi_Gate_Select_Bits(ni_m_series_gate_select));
return 0;
@@ -1135,8 +1096,8 @@ static int ni_660x_set_second_gate(struct ni_gpct *counter,
unsigned int gate_source)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
- const unsigned second_gate_reg =
- NITIO_Gi_Second_Gate_Reg(counter->counter_index);
+ unsigned cidx = counter->counter_index;
+ const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
const unsigned selected_second_gate = CR_CHAN(gate_source);
/* bits of second_gate that may be meaningful to second gate register */
static const unsigned selected_second_gate_mask = 0x1f;
@@ -1194,8 +1155,8 @@ static int ni_m_series_set_second_gate(struct ni_gpct *counter,
unsigned int gate_source)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
- const unsigned second_gate_reg =
- NITIO_Gi_Second_Gate_Reg(counter->counter_index);
+ unsigned cidx = counter->counter_index;
+ const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
const unsigned selected_second_gate = CR_CHAN(gate_source);
/* bits of second_gate that may be meaningful to second gate register */
static const unsigned selected_second_gate_mask = 0x1f;
@@ -1222,15 +1183,13 @@ int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index,
unsigned int gate_source)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
- const unsigned second_gate_reg =
- NITIO_Gi_Second_Gate_Reg(counter->counter_index);
+ unsigned cidx = counter->counter_index;
+ const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
switch (gate_index) {
case 0:
if (CR_CHAN(gate_source) == NI_GPCT_DISABLED_GATE_SELECT) {
- ni_tio_set_bits(counter,
- NITIO_Gi_Mode_Reg(counter->
- counter_index),
+ ni_tio_set_bits(counter, NITIO_MODE_REG(cidx),
Gi_Gating_Mode_Mask,
Gi_Gating_Disabled_Bits);
return 0;
@@ -1292,11 +1251,12 @@ static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned index,
unsigned int source)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
+ unsigned cidx = counter->counter_index;
if (counter_dev->variant == ni_gpct_variant_m_series) {
unsigned int abz_reg, shift, mask;
- abz_reg = NITIO_Gi_ABZ_Reg(counter->counter_index);
+ abz_reg = NITIO_ABZ_REG(cidx);
switch (index) {
case NI_GPCT_SOURCE_ENCODER_A:
shift = 10;
@@ -1319,7 +1279,6 @@ static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned index,
counter_dev->regs[abz_reg] &= ~mask;
counter_dev->regs[abz_reg] |= (source << shift) & mask;
write_register(counter, counter_dev->regs[abz_reg], abz_reg);
-/* printk("%s %x %d %d\n", __func__, counter_dev->regs[abz_reg], index, source); */
return 0;
}
return -EINVAL;
@@ -1491,12 +1450,10 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index,
unsigned int *gate_source)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
- const unsigned mode_bits = ni_tio_get_soft_copy(counter,
- NITIO_Gi_Mode_Reg
- (counter->
- counter_index));
- const unsigned second_gate_reg =
- NITIO_Gi_Second_Gate_Reg(counter->counter_index);
+ unsigned cidx = counter->counter_index;
+ const unsigned mode_bits =
+ ni_tio_get_soft_copy(counter, NITIO_MODE_REG(cidx));
+ const unsigned second_gate_reg = NITIO_GATE2_REG(cidx);
unsigned gate_select_bits;
switch (gate_index) {
@@ -1508,8 +1465,7 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index,
} else {
gate_select_bits =
(ni_tio_get_soft_copy(counter,
- NITIO_Gi_Input_Select_Reg
- (counter->counter_index)) &
+ NITIO_INPUT_SEL_REG(cidx)) &
Gi_Gate_Select_Mask) >> Gi_Gate_Select_Shift;
}
switch (counter_dev->variant) {
@@ -1577,9 +1533,13 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index,
return 0;
}
-int ni_tio_insn_config(struct ni_gpct *counter,
- struct comedi_insn *insn, unsigned int *data)
+int ni_tio_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ struct ni_gpct *counter = s->private;
+
switch (data[0]) {
case INSN_CONFIG_SET_COUNTER_MODE:
return ni_tio_set_counter_mode(counter, data[1]);
@@ -1623,11 +1583,15 @@ int ni_tio_insn_config(struct ni_gpct *counter,
}
EXPORT_SYMBOL_GPL(ni_tio_insn_config);
-int ni_tio_rinsn(struct ni_gpct *counter, struct comedi_insn *insn,
- unsigned int *data)
+int ni_tio_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ struct ni_gpct *counter = s->private;
struct ni_gpct_device *counter_dev = counter->counter_dev;
const unsigned channel = CR_CHAN(insn->chanspec);
+ unsigned cidx = counter->counter_index;
unsigned first_read;
unsigned second_read;
unsigned correct_read;
@@ -1636,65 +1600,57 @@ int ni_tio_rinsn(struct ni_gpct *counter, struct comedi_insn *insn,
return 0;
switch (channel) {
case 0:
- ni_tio_set_bits(counter,
- NITIO_Gi_Command_Reg(counter->counter_index),
+ ni_tio_set_bits(counter, NITIO_CMD_REG(cidx),
Gi_Save_Trace_Bit, 0);
- ni_tio_set_bits(counter,
- NITIO_Gi_Command_Reg(counter->counter_index),
+ ni_tio_set_bits(counter, NITIO_CMD_REG(cidx),
Gi_Save_Trace_Bit, Gi_Save_Trace_Bit);
/* The count doesn't get latched until the next clock edge, so it is possible the count
may change (once) while we are reading. Since the read of the SW_Save_Reg isn't
atomic (apparently even when it's a 32 bit register according to 660x docs),
we need to read twice and make sure the reading hasn't changed. If it has,
a third read will be correct since the count value will definitely have latched by then. */
- first_read =
- read_register(counter,
- NITIO_Gi_SW_Save_Reg(counter->counter_index));
- second_read =
- read_register(counter,
- NITIO_Gi_SW_Save_Reg(counter->counter_index));
+ first_read = read_register(counter, NITIO_SW_SAVE_REG(cidx));
+ second_read = read_register(counter, NITIO_SW_SAVE_REG(cidx));
if (first_read != second_read)
correct_read =
- read_register(counter,
- NITIO_Gi_SW_Save_Reg(counter->
- counter_index));
+ read_register(counter, NITIO_SW_SAVE_REG(cidx));
else
correct_read = first_read;
data[0] = correct_read;
return 0;
break;
case 1:
- data[0] =
- counter_dev->
- regs[NITIO_Gi_LoadA_Reg(counter->counter_index)];
+ data[0] = counter_dev->regs[NITIO_LOADA_REG(cidx)];
break;
case 2:
- data[0] =
- counter_dev->
- regs[NITIO_Gi_LoadB_Reg(counter->counter_index)];
+ data[0] = counter_dev->regs[NITIO_LOADB_REG(cidx)];
break;
}
return 0;
}
-EXPORT_SYMBOL_GPL(ni_tio_rinsn);
+EXPORT_SYMBOL_GPL(ni_tio_insn_read);
static unsigned ni_tio_next_load_register(struct ni_gpct *counter)
{
- const unsigned bits = read_register(counter,
- NITIO_Gxx_Status_Reg(counter->
- counter_index));
+ unsigned cidx = counter->counter_index;
+ const unsigned bits =
+ read_register(counter, NITIO_SHARED_STATUS_REG(cidx));
- if (bits & Gi_Next_Load_Source_Bit(counter->counter_index))
- return NITIO_Gi_LoadB_Reg(counter->counter_index);
+ if (bits & Gi_Next_Load_Source_Bit(cidx))
+ return NITIO_LOADB_REG(cidx);
else
- return NITIO_Gi_LoadA_Reg(counter->counter_index);
+ return NITIO_LOADA_REG(cidx);
}
-int ni_tio_winsn(struct ni_gpct *counter, struct comedi_insn *insn,
- unsigned int *data)
+int ni_tio_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ struct ni_gpct *counter = s->private;
struct ni_gpct_device *counter_dev = counter->counter_dev;
const unsigned channel = CR_CHAN(insn->chanspec);
+ unsigned cidx = counter->counter_index;
unsigned load_reg;
if (insn->n < 1)
@@ -1705,24 +1661,18 @@ int ni_tio_winsn(struct ni_gpct *counter, struct comedi_insn *insn,
/* Don't disturb load source select, just use whichever load register is already selected. */
load_reg = ni_tio_next_load_register(counter);
write_register(counter, data[0], load_reg);
- ni_tio_set_bits_transient(counter,
- NITIO_Gi_Command_Reg(counter->
- counter_index),
+ ni_tio_set_bits_transient(counter, NITIO_CMD_REG(cidx),
0, 0, Gi_Load_Bit);
/* restore state of load reg to whatever the user set last set it to */
write_register(counter, counter_dev->regs[load_reg], load_reg);
break;
case 1:
- counter_dev->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] =
- data[0];
- write_register(counter, data[0],
- NITIO_Gi_LoadA_Reg(counter->counter_index));
+ counter_dev->regs[NITIO_LOADA_REG(cidx)] = data[0];
+ write_register(counter, data[0], NITIO_LOADA_REG(cidx));
break;
case 2:
- counter_dev->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)] =
- data[0];
- write_register(counter, data[0],
- NITIO_Gi_LoadB_Reg(counter->counter_index));
+ counter_dev->regs[NITIO_LOADB_REG(cidx)] = data[0];
+ write_register(counter, data[0], NITIO_LOADB_REG(cidx));
break;
default:
return -EINVAL;
@@ -1730,4 +1680,19 @@ int ni_tio_winsn(struct ni_gpct *counter, struct comedi_insn *insn,
}
return 0;
}
-EXPORT_SYMBOL_GPL(ni_tio_winsn);
+EXPORT_SYMBOL_GPL(ni_tio_insn_write);
+
+static int __init ni_tio_init_module(void)
+{
+ return 0;
+}
+module_init(ni_tio_init_module);
+
+static void __exit ni_tio_cleanup_module(void)
+{
+}
+module_exit(ni_tio_cleanup_module);
+
+MODULE_AUTHOR("Comedi <comedi@comedi.org>");
+MODULE_DESCRIPTION("Comedi support for NI general-purpose counters");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_tio.h b/drivers/staging/comedi/drivers/ni_tio.h
index 7e13697b325..1056bf001e5 100644
--- a/drivers/staging/comedi/drivers/ni_tio.h
+++ b/drivers/staging/comedi/drivers/ni_tio.h
@@ -25,77 +25,77 @@ struct mite_struct;
struct ni_gpct_device;
enum ni_gpct_register {
- NITIO_G0_Autoincrement_Reg,
- NITIO_G1_Autoincrement_Reg,
- NITIO_G2_Autoincrement_Reg,
- NITIO_G3_Autoincrement_Reg,
- NITIO_G0_Command_Reg,
- NITIO_G1_Command_Reg,
- NITIO_G2_Command_Reg,
- NITIO_G3_Command_Reg,
- NITIO_G0_HW_Save_Reg,
- NITIO_G1_HW_Save_Reg,
- NITIO_G2_HW_Save_Reg,
- NITIO_G3_HW_Save_Reg,
- NITIO_G0_SW_Save_Reg,
- NITIO_G1_SW_Save_Reg,
- NITIO_G2_SW_Save_Reg,
- NITIO_G3_SW_Save_Reg,
- NITIO_G0_Mode_Reg,
- NITIO_G1_Mode_Reg,
- NITIO_G2_Mode_Reg,
- NITIO_G3_Mode_Reg,
- NITIO_G0_LoadA_Reg,
- NITIO_G1_LoadA_Reg,
- NITIO_G2_LoadA_Reg,
- NITIO_G3_LoadA_Reg,
- NITIO_G0_LoadB_Reg,
- NITIO_G1_LoadB_Reg,
- NITIO_G2_LoadB_Reg,
- NITIO_G3_LoadB_Reg,
- NITIO_G0_Input_Select_Reg,
- NITIO_G1_Input_Select_Reg,
- NITIO_G2_Input_Select_Reg,
- NITIO_G3_Input_Select_Reg,
- NITIO_G0_Counting_Mode_Reg,
- NITIO_G1_Counting_Mode_Reg,
- NITIO_G2_Counting_Mode_Reg,
- NITIO_G3_Counting_Mode_Reg,
- NITIO_G0_Second_Gate_Reg,
- NITIO_G1_Second_Gate_Reg,
- NITIO_G2_Second_Gate_Reg,
- NITIO_G3_Second_Gate_Reg,
- NITIO_G01_Status_Reg,
- NITIO_G23_Status_Reg,
- NITIO_G01_Joint_Reset_Reg,
- NITIO_G23_Joint_Reset_Reg,
- NITIO_G01_Joint_Status1_Reg,
- NITIO_G23_Joint_Status1_Reg,
- NITIO_G01_Joint_Status2_Reg,
- NITIO_G23_Joint_Status2_Reg,
- NITIO_G0_DMA_Config_Reg,
- NITIO_G1_DMA_Config_Reg,
- NITIO_G2_DMA_Config_Reg,
- NITIO_G3_DMA_Config_Reg,
- NITIO_G0_DMA_Status_Reg,
- NITIO_G1_DMA_Status_Reg,
- NITIO_G2_DMA_Status_Reg,
- NITIO_G3_DMA_Status_Reg,
- NITIO_G0_ABZ_Reg,
- NITIO_G1_ABZ_Reg,
- NITIO_G0_Interrupt_Acknowledge_Reg,
- NITIO_G1_Interrupt_Acknowledge_Reg,
- NITIO_G2_Interrupt_Acknowledge_Reg,
- NITIO_G3_Interrupt_Acknowledge_Reg,
- NITIO_G0_Status_Reg,
- NITIO_G1_Status_Reg,
- NITIO_G2_Status_Reg,
- NITIO_G3_Status_Reg,
- NITIO_G0_Interrupt_Enable_Reg,
- NITIO_G1_Interrupt_Enable_Reg,
- NITIO_G2_Interrupt_Enable_Reg,
- NITIO_G3_Interrupt_Enable_Reg,
- NITIO_Num_Registers,
+ NITIO_G0_AUTO_INC,
+ NITIO_G1_AUTO_INC,
+ NITIO_G2_AUTO_INC,
+ NITIO_G3_AUTO_INC,
+ NITIO_G0_CMD,
+ NITIO_G1_CMD,
+ NITIO_G2_CMD,
+ NITIO_G3_CMD,
+ NITIO_G0_HW_SAVE,
+ NITIO_G1_HW_SAVE,
+ NITIO_G2_HW_SAVE,
+ NITIO_G3_HW_SAVE,
+ NITIO_G0_SW_SAVE,
+ NITIO_G1_SW_SAVE,
+ NITIO_G2_SW_SAVE,
+ NITIO_G3_SW_SAVE,
+ NITIO_G0_MODE,
+ NITIO_G1_MODE,
+ NITIO_G2_MODE,
+ NITIO_G3_MODE,
+ NITIO_G0_LOADA,
+ NITIO_G1_LOADA,
+ NITIO_G2_LOADA,
+ NITIO_G3_LOADA,
+ NITIO_G0_LOADB,
+ NITIO_G1_LOADB,
+ NITIO_G2_LOADB,
+ NITIO_G3_LOADB,
+ NITIO_G0_INPUT_SEL,
+ NITIO_G1_INPUT_SEL,
+ NITIO_G2_INPUT_SEL,
+ NITIO_G3_INPUT_SEL,
+ NITIO_G0_CNT_MODE,
+ NITIO_G1_CNT_MODE,
+ NITIO_G2_CNT_MODE,
+ NITIO_G3_CNT_MODE,
+ NITIO_G0_GATE2,
+ NITIO_G1_GATE2,
+ NITIO_G2_GATE2,
+ NITIO_G3_GATE2,
+ NITIO_G01_STATUS,
+ NITIO_G23_STATUS,
+ NITIO_G01_RESET,
+ NITIO_G23_RESET,
+ NITIO_G01_STATUS1,
+ NITIO_G23_STATUS1,
+ NITIO_G01_STATUS2,
+ NITIO_G23_STATUS2,
+ NITIO_G0_DMA_CFG,
+ NITIO_G1_DMA_CFG,
+ NITIO_G2_DMA_CFG,
+ NITIO_G3_DMA_CFG,
+ NITIO_G0_DMA_STATUS,
+ NITIO_G1_DMA_STATUS,
+ NITIO_G2_DMA_STATUS,
+ NITIO_G3_DMA_STATUS,
+ NITIO_G0_ABZ,
+ NITIO_G1_ABZ,
+ NITIO_G0_INT_ACK,
+ NITIO_G1_INT_ACK,
+ NITIO_G2_INT_ACK,
+ NITIO_G3_INT_ACK,
+ NITIO_G0_STATUS,
+ NITIO_G1_STATUS,
+ NITIO_G2_STATUS,
+ NITIO_G3_STATUS,
+ NITIO_G0_INT_ENA,
+ NITIO_G1_INT_ENA,
+ NITIO_G2_INT_ENA,
+ NITIO_G3_INT_ENA,
+ NITIO_NUM_REGS,
};
enum ni_gpct_variant {
@@ -115,55 +115,42 @@ struct ni_gpct {
struct ni_gpct_device {
struct comedi_device *dev;
- void (*write_register) (struct ni_gpct *counter, unsigned bits,
- enum ni_gpct_register reg);
- unsigned (*read_register) (struct ni_gpct *counter,
- enum ni_gpct_register reg);
+ void (*write_register)(struct ni_gpct *counter, unsigned bits,
+ enum ni_gpct_register reg);
+ unsigned (*read_register)(struct ni_gpct *counter,
+ enum ni_gpct_register reg);
enum ni_gpct_variant variant;
struct ni_gpct *counters;
unsigned num_counters;
- unsigned regs[NITIO_Num_Registers];
+ unsigned regs[NITIO_NUM_REGS];
spinlock_t regs_lock;
};
-extern struct ni_gpct_device *ni_gpct_device_construct(struct comedi_device
- *dev,
- void (*write_register)
- (struct ni_gpct *
- counter, unsigned bits,
- enum ni_gpct_register
- reg),
- unsigned (*read_register)
- (struct ni_gpct *
- counter,
- enum ni_gpct_register
- reg),
- enum ni_gpct_variant
- variant,
- unsigned num_counters);
-extern void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev);
-extern void ni_tio_init_counter(struct ni_gpct *counter);
-extern int ni_tio_rinsn(struct ni_gpct *counter,
- struct comedi_insn *insn, unsigned int *data);
-extern int ni_tio_insn_config(struct ni_gpct *counter,
- struct comedi_insn *insn, unsigned int *data);
-extern int ni_tio_winsn(struct ni_gpct *counter,
- struct comedi_insn *insn, unsigned int *data);
-extern int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async);
-extern int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd);
-extern int ni_tio_cancel(struct ni_gpct *counter);
-extern void ni_tio_handle_interrupt(struct ni_gpct *counter,
- struct comedi_subdevice *s);
-extern void ni_tio_set_mite_channel(struct ni_gpct *counter,
- struct mite_channel *mite_chan);
-extern void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter,
- int *gate_error, int *tc_error,
- int *perm_stale_data,
- int *stale_data);
-
-static inline struct ni_gpct *subdev_to_counter(struct comedi_subdevice *s)
-{
- return s->private;
-}
+struct ni_gpct_device *
+ni_gpct_device_construct(struct comedi_device *,
+ void (*write_register)(struct ni_gpct *,
+ unsigned bits,
+ enum ni_gpct_register),
+ unsigned (*read_register)(struct ni_gpct *,
+ enum ni_gpct_register),
+ enum ni_gpct_variant,
+ unsigned num_counters);
+void ni_gpct_device_destroy(struct ni_gpct_device *);
+void ni_tio_init_counter(struct ni_gpct *);
+int ni_tio_insn_read(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *data);
+int ni_tio_insn_config(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *data);
+int ni_tio_insn_write(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *data);
+int ni_tio_cmd(struct comedi_device *, struct comedi_subdevice *);
+int ni_tio_cmdtest(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_cmd *);
+int ni_tio_cancel(struct ni_gpct *);
+void ni_tio_handle_interrupt(struct ni_gpct *, struct comedi_subdevice *);
+void ni_tio_set_mite_channel(struct ni_gpct *, struct mite_channel *);
+void ni_tio_acknowledge_and_confirm(struct ni_gpct *,
+ int *gate_error, int *tc_error,
+ int *perm_stale_data, int *stale_data);
#endif /* _COMEDI_NI_TIO_H */
diff --git a/drivers/staging/comedi/drivers/ni_tio_internal.h b/drivers/staging/comedi/drivers/ni_tio_internal.h
index b009876754a..15b81b8fc5c 100644
--- a/drivers/staging/comedi/drivers/ni_tio_internal.h
+++ b/drivers/staging/comedi/drivers/ni_tio_internal.h
@@ -21,409 +21,26 @@
#include "ni_tio.h"
-static inline enum ni_gpct_register NITIO_Gi_Autoincrement_Reg(unsigned
- counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_Autoincrement_Reg;
- break;
- case 1:
- return NITIO_G1_Autoincrement_Reg;
- break;
- case 2:
- return NITIO_G2_Autoincrement_Reg;
- break;
- case 3:
- return NITIO_G3_Autoincrement_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_Command_Reg(unsigned counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_Command_Reg;
- break;
- case 1:
- return NITIO_G1_Command_Reg;
- break;
- case 2:
- return NITIO_G2_Command_Reg;
- break;
- case 3:
- return NITIO_G3_Command_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_Counting_Mode_Reg(unsigned
- counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_Counting_Mode_Reg;
- break;
- case 1:
- return NITIO_G1_Counting_Mode_Reg;
- break;
- case 2:
- return NITIO_G2_Counting_Mode_Reg;
- break;
- case 3:
- return NITIO_G3_Counting_Mode_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_Input_Select_Reg(unsigned
- counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_Input_Select_Reg;
- break;
- case 1:
- return NITIO_G1_Input_Select_Reg;
- break;
- case 2:
- return NITIO_G2_Input_Select_Reg;
- break;
- case 3:
- return NITIO_G3_Input_Select_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gxx_Joint_Reset_Reg(unsigned
- counter_index)
-{
- switch (counter_index) {
- case 0:
- case 1:
- return NITIO_G01_Joint_Reset_Reg;
- break;
- case 2:
- case 3:
- return NITIO_G23_Joint_Reset_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gxx_Joint_Status1_Reg(unsigned
- counter_index)
-{
- switch (counter_index) {
- case 0:
- case 1:
- return NITIO_G01_Joint_Status1_Reg;
- break;
- case 2:
- case 3:
- return NITIO_G23_Joint_Status1_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gxx_Joint_Status2_Reg(unsigned
- counter_index)
-{
- switch (counter_index) {
- case 0:
- case 1:
- return NITIO_G01_Joint_Status2_Reg;
- break;
- case 2:
- case 3:
- return NITIO_G23_Joint_Status2_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gxx_Status_Reg(unsigned counter_index)
-{
- switch (counter_index) {
- case 0:
- case 1:
- return NITIO_G01_Status_Reg;
- break;
- case 2:
- case 3:
- return NITIO_G23_Status_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_LoadA_Reg(unsigned counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_LoadA_Reg;
- break;
- case 1:
- return NITIO_G1_LoadA_Reg;
- break;
- case 2:
- return NITIO_G2_LoadA_Reg;
- break;
- case 3:
- return NITIO_G3_LoadA_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_LoadB_Reg(unsigned counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_LoadB_Reg;
- break;
- case 1:
- return NITIO_G1_LoadB_Reg;
- break;
- case 2:
- return NITIO_G2_LoadB_Reg;
- break;
- case 3:
- return NITIO_G3_LoadB_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_Mode_Reg(unsigned counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_Mode_Reg;
- break;
- case 1:
- return NITIO_G1_Mode_Reg;
- break;
- case 2:
- return NITIO_G2_Mode_Reg;
- break;
- case 3:
- return NITIO_G3_Mode_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_SW_Save_Reg(int counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_SW_Save_Reg;
- break;
- case 1:
- return NITIO_G1_SW_Save_Reg;
- break;
- case 2:
- return NITIO_G2_SW_Save_Reg;
- break;
- case 3:
- return NITIO_G3_SW_Save_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_Second_Gate_Reg(int counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_Second_Gate_Reg;
- break;
- case 1:
- return NITIO_G1_Second_Gate_Reg;
- break;
- case 2:
- return NITIO_G2_Second_Gate_Reg;
- break;
- case 3:
- return NITIO_G3_Second_Gate_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_DMA_Config_Reg(int counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_DMA_Config_Reg;
- break;
- case 1:
- return NITIO_G1_DMA_Config_Reg;
- break;
- case 2:
- return NITIO_G2_DMA_Config_Reg;
- break;
- case 3:
- return NITIO_G3_DMA_Config_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_DMA_Status_Reg(int counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_DMA_Status_Reg;
- break;
- case 1:
- return NITIO_G1_DMA_Status_Reg;
- break;
- case 2:
- return NITIO_G2_DMA_Status_Reg;
- break;
- case 3:
- return NITIO_G3_DMA_Status_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_ABZ_Reg(int counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_ABZ_Reg;
- break;
- case 1:
- return NITIO_G1_ABZ_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_Interrupt_Acknowledge_Reg(
- int counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_Interrupt_Acknowledge_Reg;
- break;
- case 1:
- return NITIO_G1_Interrupt_Acknowledge_Reg;
- break;
- case 2:
- return NITIO_G2_Interrupt_Acknowledge_Reg;
- break;
- case 3:
- return NITIO_G3_Interrupt_Acknowledge_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_Status_Reg(int counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_Status_Reg;
- break;
- case 1:
- return NITIO_G1_Status_Reg;
- break;
- case 2:
- return NITIO_G2_Status_Reg;
- break;
- case 3:
- return NITIO_G3_Status_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
-
-static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg(
- int counter_index)
-{
- switch (counter_index) {
- case 0:
- return NITIO_G0_Interrupt_Enable_Reg;
- break;
- case 1:
- return NITIO_G1_Interrupt_Enable_Reg;
- break;
- case 2:
- return NITIO_G2_Interrupt_Enable_Reg;
- break;
- case 3:
- return NITIO_G3_Interrupt_Enable_Reg;
- break;
- default:
- BUG();
- break;
- }
- return 0;
-}
+#define NITIO_AUTO_INC_REG(x) (NITIO_G0_AUTO_INC + (x))
+#define NITIO_CMD_REG(x) (NITIO_G0_CMD + (x))
+#define NITIO_HW_SAVE_REG(x) (NITIO_G0_HW_SAVE + (x))
+#define NITIO_SW_SAVE_REG(x) (NITIO_G0_SW_SAVE + (x))
+#define NITIO_MODE_REG(x) (NITIO_G0_MODE + (x))
+#define NITIO_LOADA_REG(x) (NITIO_G0_LOADA + (x))
+#define NITIO_LOADB_REG(x) (NITIO_G0_LOADB + (x))
+#define NITIO_INPUT_SEL_REG(x) (NITIO_G0_INPUT_SEL + (x))
+#define NITIO_CNT_MODE_REG(x) (NITIO_G0_CNT_MODE + (x))
+#define NITIO_GATE2_REG(x) (NITIO_G0_GATE2 + (x))
+#define NITIO_SHARED_STATUS_REG(x) (NITIO_G01_STATUS + ((x) / 2))
+#define NITIO_RESET_REG(x) (NITIO_G01_RESET + ((x) / 2))
+#define NITIO_STATUS1_REG(x) (NITIO_G01_STATUS1 + ((x) / 2))
+#define NITIO_STATUS2_REG(x) (NITIO_G01_STATUS2 + ((x) / 2))
+#define NITIO_DMA_CFG_REG(x) (NITIO_G0_DMA_CFG + (x))
+#define NITIO_DMA_STATUS_REG(x) (NITIO_G0_DMA_STATUS + (x))
+#define NITIO_ABZ_REG(x) (NITIO_G0_ABZ + (x))
+#define NITIO_INT_ACK_REG(x) (NITIO_G0_INT_ACK + (x))
+#define NITIO_STATUS_REG(x) (NITIO_G0_STATUS + (x))
+#define NITIO_INT_ENA_REG(x) (NITIO_G0_INT_ENA + (x))
enum Gi_Auto_Increment_Reg_Bits {
Gi_Auto_Increment_Mask = 0xff
@@ -699,14 +316,14 @@ static inline unsigned Gi_Gate_Interrupt_Enable_Bit(unsigned counter_index)
static inline void write_register(struct ni_gpct *counter, unsigned bits,
enum ni_gpct_register reg)
{
- BUG_ON(reg >= NITIO_Num_Registers);
+ BUG_ON(reg >= NITIO_NUM_REGS);
counter->counter_dev->write_register(counter, bits, reg);
}
static inline unsigned read_register(struct ni_gpct *counter,
enum ni_gpct_register reg)
{
- BUG_ON(reg >= NITIO_Num_Registers);
+ BUG_ON(reg >= NITIO_NUM_REGS);
return counter->counter_dev->read_register(counter, reg);
}
@@ -738,7 +355,7 @@ static inline void ni_tio_set_bits_transient(struct ni_gpct *counter,
struct ni_gpct_device *counter_dev = counter->counter_dev;
unsigned long flags;
- BUG_ON(register_index >= NITIO_Num_Registers);
+ BUG_ON(register_index >= NITIO_NUM_REGS);
spin_lock_irqsave(&counter_dev->regs_lock, flags);
counter_dev->regs[register_index] &= ~bit_mask;
counter_dev->regs[register_index] |= (bit_values & bit_mask);
@@ -773,7 +390,7 @@ static inline unsigned ni_tio_get_soft_copy(const struct ni_gpct *counter,
unsigned long flags;
unsigned value;
- BUG_ON(register_index >= NITIO_Num_Registers);
+ BUG_ON(register_index >= NITIO_NUM_REGS);
spin_lock_irqsave(&counter_dev->regs_lock, flags);
value = counter_dev->regs[register_index];
spin_unlock_irqrestore(&counter_dev->regs_lock, flags);
diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c
index 45691efefd0..2557ab48cb6 100644
--- a/drivers/staging/comedi/drivers/ni_tiocmd.c
+++ b/drivers/staging/comedi/drivers/ni_tiocmd.c
@@ -49,14 +49,11 @@ TODO:
#include "ni_tio_internal.h"
#include "mite.h"
-MODULE_AUTHOR("Comedi <comedi@comedi.org>");
-MODULE_DESCRIPTION("Comedi command support for NI general-purpose counters");
-MODULE_LICENSE("GPL");
-
static void ni_tio_configure_dma(struct ni_gpct *counter, short enable,
short read_not_write)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
+ unsigned cidx = counter->counter_index;
unsigned input_select_bits = 0;
if (enable) {
@@ -65,8 +62,7 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable,
else
input_select_bits |= Gi_Write_Acknowledges_Irq;
}
- ni_tio_set_bits(counter,
- NITIO_Gi_Input_Select_Reg(counter->counter_index),
+ ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx),
Gi_Read_Acknowledges_Irq | Gi_Write_Acknowledges_Irq,
input_select_bits);
switch (counter_dev->variant) {
@@ -83,9 +79,7 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable,
}
if (read_not_write == 0)
gi_dma_config_bits |= Gi_DMA_Write_Bit;
- ni_tio_set_bits(counter,
- NITIO_Gi_DMA_Config_Reg(counter->
- counter_index),
+ ni_tio_set_bits(counter, NITIO_DMA_CFG_REG(cidx),
Gi_DMA_Enable_Bit | Gi_DMA_Int_Bit |
Gi_DMA_Write_Bit, gi_dma_config_bits);
}
@@ -95,14 +89,16 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable,
static int ni_tio_input_inttrig(struct comedi_device *dev,
struct comedi_subdevice *s,
- unsigned int trignum)
+ unsigned int trig_num)
{
+ struct ni_gpct *counter = s->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned long flags;
int retval = 0;
- struct ni_gpct *counter = s->private;
BUG_ON(counter == NULL);
- if (trignum != 0)
+
+ if (trig_num != cmd->start_src)
return -EINVAL;
spin_lock_irqsave(&counter->lock, flags);
@@ -119,14 +115,17 @@ static int ni_tio_input_inttrig(struct comedi_device *dev,
return retval;
}
-static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async)
+static int ni_tio_input_cmd(struct comedi_subdevice *s)
{
+ struct ni_gpct *counter = s->private;
struct ni_gpct_device *counter_dev = counter->counter_dev;
+ unsigned cidx = counter->counter_index;
+ struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
int retval = 0;
/* write alloc the entire buffer */
- comedi_buf_write_alloc(async, async->prealloc_bufsz);
+ comedi_buf_write_alloc(s, async->prealloc_bufsz);
counter->mite_chan->dir = COMEDI_INPUT;
switch (counter_dev->variant) {
case ni_gpct_variant_m_series:
@@ -140,8 +139,7 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async)
BUG();
break;
}
- ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index),
- Gi_Save_Trace_Bit, 0);
+ ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), Gi_Save_Trace_Bit, 0);
ni_tio_configure_dma(counter, 1, 1);
switch (cmd->start_src) {
case TRIG_NOW:
@@ -168,9 +166,10 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async)
return retval;
}
-static int ni_tio_output_cmd(struct ni_gpct *counter,
- struct comedi_async *async)
+static int ni_tio_output_cmd(struct comedi_subdevice *s)
{
+ struct ni_gpct *counter = s->private;
+
dev_err(counter->counter_dev->dev->class_dev,
"output commands not yet implemented.\n");
return -ENOTSUPP;
@@ -182,9 +181,11 @@ static int ni_tio_output_cmd(struct ni_gpct *counter,
return ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE);
}
-static int ni_tio_cmd_setup(struct ni_gpct *counter, struct comedi_async *async)
+static int ni_tio_cmd_setup(struct comedi_subdevice *s)
{
- struct comedi_cmd *cmd = &async->cmd;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ struct ni_gpct *counter = s->private;
+ unsigned cidx = counter->counter_index;
int set_gate_source = 0;
unsigned gate_source;
int retval = 0;
@@ -199,19 +200,17 @@ static int ni_tio_cmd_setup(struct ni_gpct *counter, struct comedi_async *async)
if (set_gate_source)
retval = ni_tio_set_gate_src(counter, 0, gate_source);
if (cmd->flags & TRIG_WAKE_EOS) {
- ni_tio_set_bits(counter,
- NITIO_Gi_Interrupt_Enable_Reg(counter->
- counter_index),
- Gi_Gate_Interrupt_Enable_Bit(counter->
- counter_index),
- Gi_Gate_Interrupt_Enable_Bit(counter->
- counter_index));
+ ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx),
+ Gi_Gate_Interrupt_Enable_Bit(cidx),
+ Gi_Gate_Interrupt_Enable_Bit(cidx));
}
return retval;
}
-int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async)
+int ni_tio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ struct ni_gpct *counter = s->private;
+ struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
int retval = 0;
unsigned long flags;
@@ -224,12 +223,12 @@ int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async)
"Interrupt-driven commands not yet implemented.\n");
retval = -EIO;
} else {
- retval = ni_tio_cmd_setup(counter, async);
+ retval = ni_tio_cmd_setup(s);
if (retval == 0) {
if (cmd->flags & CMDF_WRITE)
- retval = ni_tio_output_cmd(counter, async);
+ retval = ni_tio_output_cmd(s);
else
- retval = ni_tio_input_cmd(counter, async);
+ retval = ni_tio_input_cmd(s);
}
}
spin_unlock_irqrestore(&counter->lock, flags);
@@ -237,8 +236,11 @@ int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async)
}
EXPORT_SYMBOL_GPL(ni_tio_cmd);
-int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd)
+int ni_tio_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
{
+ struct ni_gpct *counter = s->private;
int err = 0;
unsigned int sources;
@@ -275,8 +277,16 @@ int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd)
/* Step 3: check if arguments are trivially valid */
- if (cmd->start_src != TRIG_EXT)
+ switch (cmd->start_src) {
+ case TRIG_NOW:
+ case TRIG_INT:
+ case TRIG_OTHER:
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ break;
+ case TRIG_EXT:
+ /* start_arg is the start_trigger passed to ni_tio_arm() */
+ break;
+ }
if (cmd->scan_begin_src != TRIG_EXT)
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
@@ -301,6 +311,7 @@ EXPORT_SYMBOL_GPL(ni_tio_cmdtest);
int ni_tio_cancel(struct ni_gpct *counter)
{
+ unsigned cidx = counter->counter_index;
unsigned long flags;
ni_tio_arm(counter, 0, 0);
@@ -310,10 +321,8 @@ int ni_tio_cancel(struct ni_gpct *counter)
spin_unlock_irqrestore(&counter->lock, flags);
ni_tio_configure_dma(counter, 0, 0);
- ni_tio_set_bits(counter,
- NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index),
- Gi_Gate_Interrupt_Enable_Bit(counter->counter_index),
- 0x0);
+ ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx),
+ Gi_Gate_Interrupt_Enable_Bit(cidx), 0x0);
return 0;
}
EXPORT_SYMBOL_GPL(ni_tio_cancel);
@@ -353,14 +362,11 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error,
int *tc_error, int *perm_stale_data,
int *stale_data)
{
+ unsigned cidx = counter->counter_index;
const unsigned short gxx_status = read_register(counter,
- NITIO_Gxx_Status_Reg
- (counter->
- counter_index));
+ NITIO_SHARED_STATUS_REG(cidx));
const unsigned short gi_status = read_register(counter,
- NITIO_Gi_Status_Reg
- (counter->
- counter_index));
+ NITIO_STATUS_REG(cidx));
unsigned ack = 0;
if (gate_error)
@@ -372,8 +378,8 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error,
if (stale_data)
*stale_data = 0;
- if (gxx_status & Gi_Gate_Error_Bit(counter->counter_index)) {
- ack |= Gi_Gate_Error_Confirm_Bit(counter->counter_index);
+ if (gxx_status & Gi_Gate_Error_Bit(cidx)) {
+ ack |= Gi_Gate_Error_Confirm_Bit(cidx);
if (gate_error) {
/*660x don't support automatic acknowledgement
of gate interrupt via dma read/write
@@ -384,8 +390,8 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error,
}
}
}
- if (gxx_status & Gi_TC_Error_Bit(counter->counter_index)) {
- ack |= Gi_TC_Error_Confirm_Bit(counter->counter_index);
+ if (gxx_status & Gi_TC_Error_Bit(cidx)) {
+ ack |= Gi_TC_Error_Confirm_Bit(cidx);
if (tc_error)
*tc_error = 1;
}
@@ -396,21 +402,15 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error,
ack |= Gi_Gate_Interrupt_Ack_Bit;
}
if (ack)
- write_register(counter, ack,
- NITIO_Gi_Interrupt_Acknowledge_Reg
- (counter->counter_index));
- if (ni_tio_get_soft_copy
- (counter,
- NITIO_Gi_Mode_Reg(counter->counter_index)) &
+ write_register(counter, ack, NITIO_INT_ACK_REG(cidx));
+ if (ni_tio_get_soft_copy(counter, NITIO_MODE_REG(cidx)) &
Gi_Loading_On_Gate_Bit) {
- if (gxx_status & Gi_Stale_Data_Bit(counter->counter_index)) {
+ if (gxx_status & Gi_Stale_Data_Bit(cidx)) {
if (stale_data)
*stale_data = 1;
}
- if (read_register(counter,
- NITIO_Gxx_Joint_Status2_Reg
- (counter->counter_index)) &
- Gi_Permanent_Stale_Bit(counter->counter_index)) {
+ if (read_register(counter, NITIO_STATUS2_REG(cidx)) &
+ Gi_Permanent_Stale_Bit(cidx)) {
dev_info(counter->counter_dev->dev->class_dev,
"%s: Gi_Permanent_Stale_Data detected.\n",
__func__);
@@ -424,6 +424,7 @@ EXPORT_SYMBOL_GPL(ni_tio_acknowledge_and_confirm);
void ni_tio_handle_interrupt(struct ni_gpct *counter,
struct comedi_subdevice *s)
{
+ unsigned cidx = counter->counter_index;
unsigned gpct_mite_status;
unsigned long flags;
int gate_error;
@@ -442,9 +443,8 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter,
switch (counter->counter_dev->variant) {
case ni_gpct_variant_m_series:
case ni_gpct_variant_660x:
- if (read_register(counter,
- NITIO_Gi_DMA_Status_Reg
- (counter->counter_index)) & Gi_DRQ_Error_Bit) {
+ if (read_register(counter, NITIO_DMA_STATUS_REG(cidx)) &
+ Gi_DRQ_Error_Bit) {
dev_notice(counter->counter_dev->dev->class_dev,
"%s: Gi_DRQ_Error detected.\n", __func__);
s->async->events |= COMEDI_CB_OVERFLOW;
@@ -464,7 +464,7 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter,
counter->mite_chan->mite->mite_io_addr +
MITE_CHOR(counter->mite_chan->channel));
}
- mite_sync_input_dma(counter->mite_chan, s->async);
+ mite_sync_input_dma(counter->mite_chan, s);
spin_unlock_irqrestore(&counter->lock, flags);
}
EXPORT_SYMBOL_GPL(ni_tio_handle_interrupt);
@@ -484,11 +484,13 @@ static int __init ni_tiocmd_init_module(void)
{
return 0;
}
-
module_init(ni_tiocmd_init_module);
static void __exit ni_tiocmd_cleanup_module(void)
{
}
-
module_exit(ni_tiocmd_cleanup_module);
+
+MODULE_AUTHOR("Comedi <comedi@comedi.org>");
+MODULE_DESCRIPTION("Comedi command support for NI general-purpose counters");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index f0fc123ef56..c38d97a9a89 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -202,6 +202,7 @@ static irqreturn_t pcl711_interrupt(int irq, void *d)
struct comedi_device *dev = d;
struct pcl711_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned int data;
if (!dev->attached) {
@@ -213,12 +214,11 @@ static irqreturn_t pcl711_interrupt(int irq, void *d)
outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG);
- if (comedi_buf_put(s->async, data) == 0) {
+ if (comedi_buf_put(s, data) == 0) {
s->async->events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
} else {
s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
- if (s->async->cmd.stop_src == TRIG_COUNT &&
- !(--devpriv->ntrig)) {
+ if (cmd->stop_src == TRIG_COUNT && !(--devpriv->ntrig)) {
pcl711_ai_set_mode(dev, PCL711_MODE_SOFTTRIG);
s->async->events |= COMEDI_CB_EOA;
}
@@ -253,18 +253,17 @@ static void pcl711_set_changain(struct comedi_device *dev,
outb(mux | PCL711_MUX_CHAN(chan), dev->iobase + PCL711_MUX_REG);
}
-static int pcl711_ai_wait_for_eoc(struct comedi_device *dev,
- unsigned int timeout)
+static int pcl711_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- unsigned int msb;
+ unsigned int status;
- while (timeout--) {
- msb = inb(dev->iobase + PCL711_AI_MSB_REG);
- if ((msb & PCL711_AI_MSB_DRDY) == 0)
- return 0;
- udelay(1);
- }
- return -ETIME;
+ status = inb(dev->iobase + PCL711_AI_MSB_REG);
+ if ((status & PCL711_AI_MSB_DRDY) == 0)
+ return 0;
+ return -EBUSY;
}
static int pcl711_ai_insn_read(struct comedi_device *dev,
@@ -282,7 +281,7 @@ static int pcl711_ai_insn_read(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
outb(PCL711_SOFTTRIG, dev->iobase + PCL711_SOFTTRIG_REG);
- ret = pcl711_ai_wait_for_eoc(dev, 100);
+ ret = comedi_timeout(dev, s, insn, pcl711_ai_eoc, 0);
if (ret)
return ret;
@@ -296,8 +295,8 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
struct pcl711_private *devpriv = dev->private;
- int tmp;
int err = 0;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -336,11 +335,8 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_NONE) {
+ if (cmd->stop_src == TRIG_NONE)
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
- } else {
- /* ignore */
- }
if (err)
return 3;
@@ -348,14 +344,12 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev,
/* step 4 */
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
+ arg = cmd->scan_begin_arg;
i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ,
&devpriv->divisor1,
&devpriv->divisor2,
- &cmd->scan_begin_arg,
- cmd->flags);
- if (tmp != cmd->scan_begin_arg)
- err++;
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
if (err)
@@ -364,6 +358,18 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev,
return 0;
}
+static void pcl711_ai_load_counters(struct comedi_device *dev)
+{
+ struct pcl711_private *devpriv = dev->private;
+ unsigned long timer_base = dev->iobase + PCL711_TIMER_BASE;
+
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
+
+ i8254_write(timer_base, 0, 1, devpriv->divisor1);
+ i8254_write(timer_base, 0, 2, devpriv->divisor2);
+}
+
static int pcl711_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct pcl711_private *devpriv = dev->private;
@@ -382,13 +388,8 @@ static int pcl711_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
if (cmd->scan_begin_src == TRIG_TIMER) {
- i8254_load(dev->iobase + PCL711_TIMER_BASE, 0,
- 1, devpriv->divisor1, I8254_MODE2 | I8254_BINARY);
- i8254_load(dev->iobase + PCL711_TIMER_BASE, 0,
- 2, devpriv->divisor2, I8254_MODE2 | I8254_BINARY);
-
+ pcl711_ai_load_counters(dev);
outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG);
-
pcl711_ai_set_mode(dev, PCL711_MODE_PACER_IRQ);
} else {
pcl711_ai_set_mode(dev, PCL711_MODE_EXT_IRQ);
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index cf9568ee46e..74f6489bd12 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -197,7 +197,7 @@ static int pcl726_intr_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
- err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
if (err)
@@ -240,7 +240,7 @@ static irqreturn_t pcl726_interrupt(int irq, void *d)
if (devpriv->cmd_running) {
pcl726_intr_cancel(dev, s);
- comedi_buf_put(s->async, 0);
+ comedi_buf_put(s, 0);
s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
comedi_event(dev, s);
}
@@ -430,6 +430,7 @@ static int pcl726_attach(struct comedi_device *dev,
s->maxdata = 1;
s->range_table = &range_digital;
s->insn_bits = pcl726_intr_insn_bits;
+ s->len_chanlist = 1;
s->do_cmdtest = pcl726_intr_cmdtest;
s->do_cmd = pcl726_intr_cmd;
s->cancel = pcl726_intr_cancel;
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index 2baaf1db6fb..7fb044ce399 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -17,6 +17,8 @@
* (ICP) P16R16-DIO [p16r16dio]
* (Advantech) PCL-733 [pcl733]
* (Advantech) PCL-734 [pcl734]
+ * (Diamond Systems) OPMM-1616-XT [opmm-1616-xt]
+ * (Diamond Systems) PEARL-MM-P [prearl-mm-p]
* Author: José Luis Sánchez (jsanchezv@teleline.es)
* Status: untested
*
@@ -70,6 +72,27 @@
* BASE+1 Isolated outputs 8-15 (write) or inputs 8-15 (read)
* BASE+2 Isolated outputs 16-23 (write) or inputs 16-23 (read)
* BASE+3 Isolated outputs 24-31 (write) or inputs 24-31 (read)
+ *
+ * The opmm-1616-xt board has this register mapping:
+ *
+ * BASE+0 Isolated outputs 0-7 (write) (read back)
+ * BASE+1 Isolated outputs 8-15 (write) (read back)
+ * BASE+2 Isolated inputs 0-7 (read)
+ * BASE+3 Isolated inputs 8-15 (read)
+ *
+ * These registers are not currently supported:
+ *
+ * BASE+2 Relay select register (write)
+ * BASE+3 Board reset control register (write)
+ * BASE+4 Interrupt control register (write)
+ * BASE+4 Change detect 7-0 status register (read)
+ * BASE+5 LED control register (write)
+ * BASE+5 Change detect 15-8 status register (read)
+ *
+ * The pearl-mm-p board has this register mapping:
+ *
+ * BASE+0 Isolated outputs 0-7 (write)
+ * BASE+1 Isolated outputs 8-15 (write)
*/
struct pcl730_board {
@@ -158,6 +181,19 @@ static const struct pcl730_board pcl730_boards[] = {
.io_range = 0x04,
.n_subdevs = 1,
.n_iso_out_chan = 32,
+ }, {
+ .name = "opmm-1616-xt",
+ .io_range = 0x10,
+ .is_acl7225b = 1,
+ .has_readback = 1,
+ .n_subdevs = 2,
+ .n_iso_out_chan = 16,
+ .n_iso_in_chan = 16,
+ }, {
+ .name = "pearl-mm-p",
+ .io_range = 0x02,
+ .n_subdevs = 1,
+ .n_iso_out_chan = 16,
},
};
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index 03315abcca1..4c1b9470647 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -131,401 +131,586 @@
#define boardACL8216 8 /* and ICP DAS A-826PG */
#define boardA821 9 /* PGH, PGL, PGL/NDA versions */
-#define PCLx1x_IORANGE 16
-
-#define PCL812_CTR0 0
-#define PCL812_CTR1 1
-#define PCL812_CTR2 2
-#define PCL812_CTRCTL 3
-#define PCL812_AD_LO 4
-#define PCL812_DA1_LO 4
-#define PCL812_AD_HI 5
-#define PCL812_DA1_HI 5
-#define PCL812_DA2_LO 6
-#define PCL812_DI_LO 6
-#define PCL812_DA2_HI 7
-#define PCL812_DI_HI 7
-#define PCL812_CLRINT 8
-#define PCL812_GAIN 9
-#define PCL812_MUX 10
-#define PCL812_MODE 11
-#define PCL812_CNTENABLE 10
-#define PCL812_SOFTTRIG 12
-#define PCL812_DO_LO 13
-#define PCL812_DO_HI 14
-
-#define PCL812_DRDY 0x10 /* =0 data ready */
-
-#define ACL8216_STATUS 8 /* 5. bit signalize data ready */
-
-#define ACL8216_DRDY 0x20 /* =0 data ready */
+/*
+ * Register I/O map
+ */
+#define PCL812_TIMER_BASE 0x00
+#define PCL812_AI_LSB_REG 0x04
+#define PCL812_AI_MSB_REG 0x05
+#define PCL812_AI_MSB_DRDY (1 << 4)
+#define PCL812_AO_LSB_REG(x) (0x04 + ((x) * 2))
+#define PCL812_AO_MSB_REG(x) (0x05 + ((x) * 2))
+#define PCL812_DI_LSB_REG 0x06
+#define PCL812_DI_MSB_REG 0x07
+#define PCL812_STATUS_REG 0x08
+#define PCL812_STATUS_DRDY (1 << 5)
+#define PCL812_RANGE_REG 0x09
+#define PCL812_MUX_REG 0x0a
+#define PCL812_MUX_CHAN(x) ((x) << 0)
+#define PCL812_MUX_CS0 (1 << 4)
+#define PCL812_MUX_CS1 (1 << 5)
+#define PCL812_CTRL_REG 0x0b
+#define PCL812_CTRL_DISABLE_TRIG (0 << 0)
+#define PCL812_CTRL_SOFT_TRIG (1 << 0)
+#define PCL812_CTRL_PACER_DMA_TRIG (2 << 0)
+#define PCL812_CTRL_PACER_EOC_TRIG (6 << 0)
+#define PCL812_SOFTTRIG_REG 0x0c
+#define PCL812_DO_LSB_REG 0x0d
+#define PCL812_DO_MSB_REG 0x0e
#define MAX_CHANLIST_LEN 256 /* length of scan list */
-static const struct comedi_lrange range_pcl812pg_ai = { 5, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- BIP_RANGE(0.3125),
- }
+static const struct comedi_lrange range_pcl812pg_ai = {
+ 5, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ BIP_RANGE(0.3125)
+ }
};
-static const struct comedi_lrange range_pcl812pg2_ai = { 5, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- }
+static const struct comedi_lrange range_pcl812pg2_ai = {
+ 5, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625)
+ }
};
-static const struct comedi_lrange range812_bipolar1_25 = { 1, {
- BIP_RANGE(1.25),
- }
+static const struct comedi_lrange range812_bipolar1_25 = {
+ 1, {
+ BIP_RANGE(1.25)
+ }
};
-static const struct comedi_lrange range812_bipolar0_625 = { 1, {
- BIP_RANGE
- (0.625),
- }
+static const struct comedi_lrange range812_bipolar0_625 = {
+ 1, {
+ BIP_RANGE(0.625)
+ }
};
-static const struct comedi_lrange range812_bipolar0_3125 = { 1, {
- BIP_RANGE
- (0.3125),
- }
+static const struct comedi_lrange range812_bipolar0_3125 = {
+ 1, {
+ BIP_RANGE(0.3125)
+ }
};
-static const struct comedi_lrange range_pcl813b_ai = { 4, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- }
+static const struct comedi_lrange range_pcl813b_ai = {
+ 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625)
+ }
};
-static const struct comedi_lrange range_pcl813b2_ai = { 4, {
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25),
- }
+static const struct comedi_lrange range_pcl813b2_ai = {
+ 4, {
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
-static const struct comedi_lrange range_iso813_1_ai = { 5, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- BIP_RANGE(0.3125),
- }
+static const struct comedi_lrange range_iso813_1_ai = {
+ 5, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ BIP_RANGE(0.3125)
+ }
};
-static const struct comedi_lrange range_iso813_1_2_ai = { 5, {
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25),
- UNI_RANGE(0.625),
- }
+static const struct comedi_lrange range_iso813_1_2_ai = {
+ 5, {
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25),
+ UNI_RANGE(0.625)
+ }
};
-static const struct comedi_lrange range_iso813_2_ai = { 4, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- }
+static const struct comedi_lrange range_iso813_2_ai = {
+ 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625)
+ }
};
-static const struct comedi_lrange range_iso813_2_2_ai = { 4, {
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25),
- }
+static const struct comedi_lrange range_iso813_2_2_ai = {
+ 4, {
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
-static const struct comedi_lrange range_acl8113_1_ai = { 4, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- }
+static const struct comedi_lrange range_acl8113_1_ai = {
+ 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625)
+ }
};
-static const struct comedi_lrange range_acl8113_1_2_ai = { 4, {
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25),
- }
+static const struct comedi_lrange range_acl8113_1_2_ai = {
+ 4, {
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
-static const struct comedi_lrange range_acl8113_2_ai = { 3, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- }
+static const struct comedi_lrange range_acl8113_2_ai = {
+ 3, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25)
+ }
};
-static const struct comedi_lrange range_acl8113_2_2_ai = { 3, {
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- }
+static const struct comedi_lrange range_acl8113_2_2_ai = {
+ 3, {
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5)
+ }
};
-static const struct comedi_lrange range_acl8112dg_ai = { 9, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25),
- BIP_RANGE(10),
- }
+static const struct comedi_lrange range_acl8112dg_ai = {
+ 9, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25),
+ BIP_RANGE(10)
+ }
};
-static const struct comedi_lrange range_acl8112hg_ai = { 12, {
- BIP_RANGE(5),
- BIP_RANGE(0.5),
- BIP_RANGE(0.05),
- BIP_RANGE(0.005),
- UNI_RANGE(10),
- UNI_RANGE(1),
- UNI_RANGE(0.1),
- UNI_RANGE(0.01),
- BIP_RANGE(10),
- BIP_RANGE(1),
- BIP_RANGE(0.1),
- BIP_RANGE(0.01),
- }
+static const struct comedi_lrange range_acl8112hg_ai = {
+ 12, {
+ BIP_RANGE(5),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.05),
+ BIP_RANGE(0.005),
+ UNI_RANGE(10),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1),
+ UNI_RANGE(0.01),
+ BIP_RANGE(10),
+ BIP_RANGE(1),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.01)
+ }
};
-static const struct comedi_lrange range_a821pgh_ai = { 4, {
- BIP_RANGE(5),
- BIP_RANGE(0.5),
- BIP_RANGE(0.05),
- BIP_RANGE(0.005),
- }
+static const struct comedi_lrange range_a821pgh_ai = {
+ 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.05),
+ BIP_RANGE(0.005)
+ }
};
struct pcl812_board {
+ const char *name;
+ int board_type;
+ int n_aichan;
+ int n_aochan;
+ unsigned int ai_ns_min;
+ const struct comedi_lrange *rangelist_ai;
+ unsigned int IRQbits;
+ unsigned int has_dma:1;
+ unsigned int has_16bit_ai:1;
+ unsigned int has_mpc508_mux:1;
+ unsigned int has_dio:1;
+};
- const char *name; /* board name */
- int board_type; /* type of this board */
- int n_aichan; /* num of AI chans in S.E. */
- int n_aichan_diff; /* DIFF num of chans */
- int n_aochan; /* num of DA chans */
- int n_dichan; /* DI and DO chans */
- int n_dochan;
- int ai_maxdata; /* AI resolution */
- unsigned int ai_ns_min; /* max sample speed of card v ns */
- unsigned int i8254_osc_base; /* clock base */
- const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
- const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
- unsigned int IRQbits; /* allowed IRQ */
- unsigned char DMAbits; /* allowed DMA chans */
- unsigned char io_range; /* iorange for this board */
- unsigned char haveMPC508; /* 1=board use MPC508A multiplexor */
+static const struct pcl812_board boardtypes[] = {
+ {
+ .name = "pcl812",
+ .board_type = boardPCL812,
+ .n_aichan = 16,
+ .n_aochan = 2,
+ .ai_ns_min = 33000,
+ .rangelist_ai = &range_bipolar10,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "pcl812pg",
+ .board_type = boardPCL812PG,
+ .n_aichan = 16,
+ .n_aochan = 2,
+ .ai_ns_min = 33000,
+ .rangelist_ai = &range_pcl812pg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "acl8112pg",
+ .board_type = boardPCL812PG,
+ .n_aichan = 16,
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_pcl812pg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "acl8112dg",
+ .board_type = boardACL8112,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_acl8112dg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_mpc508_mux = 1,
+ .has_dio = 1,
+ }, {
+ .name = "acl8112hg",
+ .board_type = boardACL8112,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_acl8112hg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_mpc508_mux = 1,
+ .has_dio = 1,
+ }, {
+ .name = "a821pgl",
+ .board_type = boardA821,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 1,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_pcl813b_ai,
+ .IRQbits = 0x000c,
+ .has_dio = 1,
+ }, {
+ .name = "a821pglnda",
+ .board_type = boardA821,
+ .n_aichan = 16, /* 8 differential */
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_pcl813b_ai,
+ .IRQbits = 0x000c,
+ }, {
+ .name = "a821pgh",
+ .board_type = boardA821,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 1,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_a821pgh_ai,
+ .IRQbits = 0x000c,
+ .has_dio = 1,
+ }, {
+ .name = "a822pgl",
+ .board_type = boardACL8112,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_acl8112dg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "a822pgh",
+ .board_type = boardACL8112,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_acl8112hg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "a823pgl",
+ .board_type = boardACL8112,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 8000,
+ .rangelist_ai = &range_acl8112dg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "a823pgh",
+ .board_type = boardACL8112,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 8000,
+ .rangelist_ai = &range_acl8112hg_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_dio = 1,
+ }, {
+ .name = "pcl813",
+ .board_type = boardPCL813,
+ .n_aichan = 32,
+ .rangelist_ai = &range_pcl813b_ai,
+ }, {
+ .name = "pcl813b",
+ .board_type = boardPCL813B,
+ .n_aichan = 32,
+ .rangelist_ai = &range_pcl813b_ai,
+ }, {
+ .name = "acl8113",
+ .board_type = boardACL8113,
+ .n_aichan = 32,
+ .rangelist_ai = &range_acl8113_1_ai,
+ }, {
+ .name = "iso813",
+ .board_type = boardISO813,
+ .n_aichan = 32,
+ .rangelist_ai = &range_iso813_1_ai,
+ }, {
+ .name = "acl8216",
+ .board_type = boardACL8216,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_pcl813b2_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_16bit_ai = 1,
+ .has_mpc508_mux = 1,
+ .has_dio = 1,
+ }, {
+ .name = "a826pg",
+ .board_type = boardACL8216,
+ .n_aichan = 16, /* 8 differential */
+ .n_aochan = 2,
+ .ai_ns_min = 10000,
+ .rangelist_ai = &range_pcl813b2_ai,
+ .IRQbits = 0xdcfc,
+ .has_dma = 1,
+ .has_16bit_ai = 1,
+ .has_dio = 1,
+ },
};
struct pcl812_private {
-
- unsigned char valid; /* =1 device is OK */
unsigned char dma; /* >0 use dma ( usedDMA channel) */
- unsigned char use_diff; /* =1 diff inputs */
- unsigned char use_MPC; /* 1=board uses MPC508A multiplexor */
- unsigned char use_ext_trg; /* 1=board uses external trigger */
unsigned char range_correction; /* =1 we must add 1 to range number */
- unsigned char old_chan_reg; /* lastly used chan/gain pair */
- unsigned char old_gain_reg;
+ unsigned int last_ai_chanspec;
unsigned char mode_reg_int; /* there is stored INT number for some card */
- unsigned char ai_neverending; /* =1 we do unlimited AI */
- unsigned char ai_eos; /* 1=EOS wake up */
- unsigned char ai_dma; /* =1 we use DMA */
unsigned int ai_poll_ptr; /* how many sampes transfer poll */
- unsigned int ai_scans; /* len of scanlist */
unsigned int ai_act_scan; /* how many scans we finished */
- unsigned int ai_chanlist[MAX_CHANLIST_LEN]; /* our copy of channel/range list */
- unsigned int ai_n_chan; /* how many channels is measured */
- unsigned int ai_flags; /* flaglist */
- unsigned int ai_data_len; /* len of data buffer */
- unsigned int ai_is16b; /* =1 we have 16 bit card */
+ unsigned int dmapages;
+ unsigned int hwdmasize;
unsigned long dmabuf[2]; /* PTR to DMA buf */
- unsigned int dmapages[2]; /* how many pages we have allocated */
unsigned int hwdmaptr[2]; /* HW PTR to DMA buf */
- unsigned int hwdmasize[2]; /* DMA buf size in bytes */
unsigned int dmabytestomove[2]; /* how many bytes DMA transfer */
int next_dma_buf; /* which buffer is next to use */
unsigned int dma_runs_to_end; /* how many times we must switch DMA buffers */
unsigned int last_dma_run; /* how many bytes to transfer on last DMA buffer */
unsigned int max_812_ai_mode0_rangewait; /* setling time for gain */
unsigned int ao_readback[2]; /* data for AO readback */
+ unsigned int divisor1;
+ unsigned int divisor2;
+ unsigned int use_diff:1;
+ unsigned int use_mpc508:1;
+ unsigned int use_ext_trg:1;
+ unsigned int ai_dma:1;
+ unsigned int ai_eos:1;
};
-/*
-==============================================================================
-*/
-static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2);
-static void setup_range_channel(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int rangechan, char wait);
-static int pcl812_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-/*
-==============================================================================
-*/
-static int pcl812_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl812_start_pacer(struct comedi_device *dev, bool load_timers)
{
struct pcl812_private *devpriv = dev->private;
- int n;
- int timeout, hi;
-
- /* select software trigger */
- outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE);
- /* select channel and renge */
- setup_range_channel(dev, s, insn->chanspec, 1);
- for (n = 0; n < insn->n; n++) {
- /* start conversion */
- outb(255, dev->iobase + PCL812_SOFTTRIG);
- udelay(5);
- timeout = 50; /* wait max 50us, it must finish under 33us */
- while (timeout--) {
- hi = inb(dev->iobase + PCL812_AD_HI);
- if (!(hi & PCL812_DRDY))
- goto conv_finish;
- udelay(1);
- }
- printk
- ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n",
- dev->minor, dev->board_name, dev->iobase);
- outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
- return -ETIME;
-
-conv_finish:
- data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO);
+ unsigned long timer_base = dev->iobase + PCL812_TIMER_BASE;
+
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ udelay(1);
+
+ if (load_timers) {
+ i8254_write(timer_base, 0, 2, devpriv->divisor2);
+ i8254_write(timer_base, 0, 1, devpriv->divisor1);
}
- outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
- return n;
}
-/*
-==============================================================================
-*/
-static int acl8216_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl812_ai_setup_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- int n;
- int timeout;
-
- /* select software trigger */
- outb(1, dev->iobase + PCL812_MODE);
- /* select channel and renge */
- setup_range_channel(dev, s, insn->chanspec, 1);
- for (n = 0; n < insn->n; n++) {
- /* start conversion */
- outb(255, dev->iobase + PCL812_SOFTTRIG);
- udelay(5);
- timeout = 50; /* wait max 50us, it must finish under 33us */
- while (timeout--) {
- if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY))
- goto conv_finish;
- udelay(1);
+ struct pcl812_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int dma_flags;
+ unsigned int bytes;
+
+ /* we use EOS, so adapt DMA buffer to one scan */
+ if (devpriv->ai_eos) {
+ devpriv->dmabytestomove[0] = cfc_bytes_per_scan(s);
+ devpriv->dmabytestomove[1] = cfc_bytes_per_scan(s);
+ devpriv->dma_runs_to_end = 1;
+ } else {
+ devpriv->dmabytestomove[0] = devpriv->hwdmasize;
+ devpriv->dmabytestomove[1] = devpriv->hwdmasize;
+ if (s->async->prealloc_bufsz < devpriv->hwdmasize) {
+ devpriv->dmabytestomove[0] =
+ s->async->prealloc_bufsz;
+ devpriv->dmabytestomove[1] =
+ s->async->prealloc_bufsz;
}
- printk
- ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n",
- dev->minor, dev->board_name, dev->iobase);
- outb(0, dev->iobase + PCL812_MODE);
- return -ETIME;
-
-conv_finish:
- data[n] =
- (inb(dev->iobase +
- PCL812_AD_HI) << 8) | inb(dev->iobase + PCL812_AD_LO);
+ if (cmd->stop_src == TRIG_NONE) {
+ devpriv->dma_runs_to_end = 1;
+ } else {
+ /* how many samples we must transfer? */
+ bytes = cmd->stop_arg * cfc_bytes_per_scan(s);
+
+ /* how many DMA pages we must fill */
+ devpriv->dma_runs_to_end =
+ bytes / devpriv->dmabytestomove[0];
+
+ /* on last dma transfer must be moved */
+ devpriv->last_dma_run =
+ bytes % devpriv->dmabytestomove[0];
+ if (devpriv->dma_runs_to_end == 0)
+ devpriv->dmabytestomove[0] =
+ devpriv->last_dma_run;
+ devpriv->dma_runs_to_end--;
+ }
+ }
+ if (devpriv->dmabytestomove[0] > devpriv->hwdmasize) {
+ devpriv->dmabytestomove[0] = devpriv->hwdmasize;
+ devpriv->ai_eos = 0;
+ }
+ if (devpriv->dmabytestomove[1] > devpriv->hwdmasize) {
+ devpriv->dmabytestomove[1] = devpriv->hwdmasize;
+ devpriv->ai_eos = 0;
}
- outb(0, dev->iobase + PCL812_MODE);
- return n;
+ devpriv->next_dma_buf = 0;
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ dma_flags = claim_dma_lock();
+ clear_dma_ff(devpriv->dma);
+ set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
+ set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]);
+ release_dma_lock(dma_flags);
+ enable_dma(devpriv->dma);
}
-/*
-==============================================================================
-*/
-static int pcl812_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl812_ai_setup_next_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct pcl812_private *devpriv = dev->private;
- int chan = CR_CHAN(insn->chanspec);
- int i;
+ unsigned long dma_flags;
- for (i = 0; i < insn->n; i++) {
- outb((data[i] & 0xff),
- dev->iobase + (chan ? PCL812_DA2_LO : PCL812_DA1_LO));
- outb((data[i] >> 8) & 0x0f,
- dev->iobase + (chan ? PCL812_DA2_HI : PCL812_DA1_HI));
- devpriv->ao_readback[chan] = data[i];
+ devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
+ disable_dma(devpriv->dma);
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ dma_flags = claim_dma_lock();
+ set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
+ if (devpriv->ai_eos) {
+ set_dma_count(devpriv->dma,
+ devpriv->dmabytestomove[devpriv->next_dma_buf]);
+ } else {
+ if (devpriv->dma_runs_to_end) {
+ set_dma_count(devpriv->dma,
+ devpriv->dmabytestomove[devpriv->
+ next_dma_buf]);
+ } else {
+ set_dma_count(devpriv->dma, devpriv->last_dma_run);
+ }
+ devpriv->dma_runs_to_end--;
}
-
- return i;
+ release_dma_lock(dma_flags);
+ enable_dma(devpriv->dma);
}
-/*
-==============================================================================
-*/
-static int pcl812_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl812_ai_set_chan_range(struct comedi_device *dev,
+ unsigned int chanspec, char wait)
{
struct pcl812_private *devpriv = dev->private;
- int chan = CR_CHAN(insn->chanspec);
- int i;
+ unsigned int chan = CR_CHAN(chanspec);
+ unsigned int range = CR_RANGE(chanspec);
+ unsigned int mux = 0;
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
+ if (chanspec == devpriv->last_ai_chanspec)
+ return;
+
+ devpriv->last_ai_chanspec = chanspec;
+
+ if (devpriv->use_mpc508) {
+ if (devpriv->use_diff) {
+ mux |= PCL812_MUX_CS0 | PCL812_MUX_CS1;
+ } else {
+ if (chan < 8)
+ mux |= PCL812_MUX_CS0;
+ else
+ mux |= PCL812_MUX_CS1;
+ }
+ }
+
+ outb(mux | PCL812_MUX_CHAN(chan), dev->iobase + PCL812_MUX_REG);
+ outb(range + devpriv->range_correction, dev->iobase + PCL812_RANGE_REG);
- return i;
+ if (wait)
+ /*
+ * XXX this depends on selected range and can be very long for
+ * some high gain ranges!
+ */
+ udelay(devpriv->max_812_ai_mode0_rangewait);
}
-/*
-==============================================================================
-*/
-static int pcl812_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl812_ai_clear_eoc(struct comedi_device *dev)
{
- data[1] = inb(dev->iobase + PCL812_DI_LO);
- data[1] |= inb(dev->iobase + PCL812_DI_HI) << 8;
+ /* writing any value clears the interrupt request */
+ outb(0, dev->iobase + PCL812_STATUS_REG);
+}
- return insn->n;
+static void pcl812_ai_soft_trig(struct comedi_device *dev)
+{
+ /* writing any value triggers a software conversion */
+ outb(255, dev->iobase + PCL812_SOFTTRIG_REG);
}
-static int pcl812_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static unsigned int pcl812_ai_get_sample(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- if (comedi_dio_update_state(s, data)) {
- outb(s->state & 0xff, dev->iobase + PCL812_DO_LO);
- outb((s->state >> 8), dev->iobase + PCL812_DO_HI);
- }
+ unsigned int val;
- data[1] = s->state;
+ val = inb(dev->iobase + PCL812_AI_MSB_REG) << 8;
+ val |= inb(dev->iobase + PCL812_AI_LSB_REG);
- return insn->n;
+ return val & s->maxdata;
+}
+
+static int pcl812_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ if (s->maxdata > 0x0fff) {
+ status = inb(dev->iobase + PCL812_STATUS_REG);
+ if ((status & PCL812_STATUS_DRDY) == 0)
+ return 0;
+ } else {
+ status = inb(dev->iobase + PCL812_AI_MSB_REG);
+ if ((status & PCL812_AI_MSB_DRDY) == 0)
+ return 0;
+ }
+ return -EBUSY;
}
-/*
-==============================================================================
-*/
static int pcl812_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
@@ -533,7 +718,7 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
struct pcl812_private *devpriv = dev->private;
int err = 0;
unsigned int flags;
- int tmp, divisor1, divisor2;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -573,7 +758,6 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
- err |= cfc_check_trigger_arg_max(&cmd->chanlist_len, MAX_CHANLIST_LEN);
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
if (cmd->stop_src == TRIG_COUNT)
@@ -587,14 +771,12 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
- i8253_cascade_ns_to_timer(board->i8254_osc_base,
- &divisor1, &divisor2,
- &cmd->convert_arg, cmd->flags);
- if (cmd->convert_arg < board->ai_ns_min)
- cmd->convert_arg = board->ai_ns_min;
- if (tmp != cmd->convert_arg)
- err++;
+ arg = cmd->convert_arg;
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ,
+ &devpriv->divisor1,
+ &devpriv->divisor2,
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
}
if (err)
@@ -603,69 +785,27 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
return 0;
}
-/*
-==============================================================================
-*/
static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
- const struct pcl812_board *board = comedi_board(dev);
struct pcl812_private *devpriv = dev->private;
- unsigned int divisor1 = 0, divisor2 = 0, i, dma_flags, bytes;
struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int ctrl = 0;
+ unsigned int i;
- if (cmd->start_src != TRIG_NOW)
- return -EINVAL;
- if (cmd->scan_begin_src != TRIG_FOLLOW)
- return -EINVAL;
- if (devpriv->use_ext_trg) {
- if (cmd->convert_src != TRIG_EXT)
- return -EINVAL;
- } else {
- if (cmd->convert_src != TRIG_TIMER)
- return -EINVAL;
- }
- if (cmd->scan_end_src != TRIG_COUNT)
- return -EINVAL;
- if (cmd->scan_end_arg != cmd->chanlist_len)
- return -EINVAL;
- if (cmd->chanlist_len > MAX_CHANLIST_LEN)
- return -EINVAL;
-
- if (cmd->convert_src == TRIG_TIMER) {
- if (cmd->convert_arg < board->ai_ns_min)
- cmd->convert_arg = board->ai_ns_min;
- i8253_cascade_ns_to_timer(board->i8254_osc_base,
- &divisor1, &divisor2,
- &cmd->convert_arg, cmd->flags);
- }
-
- start_pacer(dev, -1, 0, 0); /* stop pacer */
+ pcl812_start_pacer(dev, false);
- devpriv->ai_n_chan = cmd->chanlist_len;
- memcpy(devpriv->ai_chanlist, cmd->chanlist,
- sizeof(unsigned int) * cmd->scan_end_arg);
- /* select first channel and range */
- setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1);
+ pcl812_ai_set_chan_range(dev, cmd->chanlist[0], 1);
if (devpriv->dma) { /* check if we can use DMA transfer */
devpriv->ai_dma = 1;
- for (i = 1; i < devpriv->ai_n_chan; i++)
- if (devpriv->ai_chanlist[0] != devpriv->ai_chanlist[i]) {
+ for (i = 1; i < cmd->chanlist_len; i++)
+ if (cmd->chanlist[0] != cmd->chanlist[i]) {
/* we cann't use DMA :-( */
devpriv->ai_dma = 0;
break;
}
- } else
- devpriv->ai_dma = 0;
-
- devpriv->ai_flags = cmd->flags;
- devpriv->ai_data_len = s->async->prealloc_bufsz;
- if (cmd->stop_src == TRIG_COUNT) {
- devpriv->ai_scans = cmd->stop_arg;
- devpriv->ai_neverending = 0;
} else {
- devpriv->ai_scans = 0;
- devpriv->ai_neverending = 1;
+ devpriv->ai_dma = 0;
}
devpriv->ai_act_scan = 0;
@@ -673,200 +813,100 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
s->async->cur_chan = 0;
/* don't we want wake up every scan? */
- if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
+ if (cmd->flags & TRIG_WAKE_EOS) {
devpriv->ai_eos = 1;
/* DMA is useless for this situation */
- if (devpriv->ai_n_chan == 1)
+ if (cmd->chanlist_len == 1)
devpriv->ai_dma = 0;
}
- if (devpriv->ai_dma) {
- /* we use EOS, so adapt DMA buffer to one scan */
- if (devpriv->ai_eos) {
- devpriv->dmabytestomove[0] =
- devpriv->ai_n_chan * sizeof(short);
- devpriv->dmabytestomove[1] =
- devpriv->ai_n_chan * sizeof(short);
- devpriv->dma_runs_to_end = 1;
- } else {
- devpriv->dmabytestomove[0] = devpriv->hwdmasize[0];
- devpriv->dmabytestomove[1] = devpriv->hwdmasize[1];
- if (devpriv->ai_data_len < devpriv->hwdmasize[0])
- devpriv->dmabytestomove[0] =
- devpriv->ai_data_len;
- if (devpriv->ai_data_len < devpriv->hwdmasize[1])
- devpriv->dmabytestomove[1] =
- devpriv->ai_data_len;
- if (devpriv->ai_neverending) {
- devpriv->dma_runs_to_end = 1;
- } else {
- /* how many samples we must transfer? */
- bytes = devpriv->ai_n_chan *
- devpriv->ai_scans * sizeof(short);
-
- /* how many DMA pages we must fill */
- devpriv->dma_runs_to_end =
- bytes / devpriv->dmabytestomove[0];
-
- /* on last dma transfer must be moved */
- devpriv->last_dma_run =
- bytes % devpriv->dmabytestomove[0];
- if (devpriv->dma_runs_to_end == 0)
- devpriv->dmabytestomove[0] =
- devpriv->last_dma_run;
- devpriv->dma_runs_to_end--;
- }
- }
- if (devpriv->dmabytestomove[0] > devpriv->hwdmasize[0]) {
- devpriv->dmabytestomove[0] = devpriv->hwdmasize[0];
- devpriv->ai_eos = 0;
- }
- if (devpriv->dmabytestomove[1] > devpriv->hwdmasize[1]) {
- devpriv->dmabytestomove[1] = devpriv->hwdmasize[1];
- devpriv->ai_eos = 0;
- }
- devpriv->next_dma_buf = 0;
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- dma_flags = claim_dma_lock();
- clear_dma_ff(devpriv->dma);
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
- set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]);
- release_dma_lock(dma_flags);
- enable_dma(devpriv->dma);
- }
+ if (devpriv->ai_dma)
+ pcl812_ai_setup_dma(dev, s);
switch (cmd->convert_src) {
case TRIG_TIMER:
- start_pacer(dev, 1, divisor1, divisor2);
+ pcl812_start_pacer(dev, true);
break;
}
- if (devpriv->ai_dma) /* let's go! */
- outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE);
- else /* let's go! */
- outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE);
+ if (devpriv->ai_dma)
+ ctrl |= PCL812_CTRL_PACER_DMA_TRIG;
+ else
+ ctrl |= PCL812_CTRL_PACER_EOC_TRIG;
+ outb(devpriv->mode_reg_int | ctrl, dev->iobase + PCL812_CTRL_REG);
return 0;
}
-/*
-==============================================================================
-*/
-static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d)
+static bool pcl812_ai_next_chan(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- char err = 1;
- unsigned int mask, timeout;
- struct comedi_device *dev = d;
struct pcl812_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
- unsigned int next_chan;
+ struct comedi_cmd *cmd = &s->async->cmd;
- s->async->events = 0;
+ s->async->events |= COMEDI_CB_BLOCK;
- timeout = 50; /* wait max 50us, it must finish under 33us */
- if (devpriv->ai_is16b) {
- mask = 0xffff;
- while (timeout--) {
- if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) {
- err = 0;
- break;
- }
- udelay(1);
- }
- } else {
- mask = 0x0fff;
- while (timeout--) {
- if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) {
- err = 0;
- break;
- }
- udelay(1);
- }
+ s->async->cur_chan++;
+ if (s->async->cur_chan >= cmd->chanlist_len) {
+ s->async->cur_chan = 0;
+ devpriv->ai_act_scan++;
+ s->async->events |= COMEDI_CB_EOS;
+ }
+
+ if (cmd->stop_src == TRIG_COUNT &&
+ devpriv->ai_act_scan >= cmd->stop_arg) {
+ /* all data sampled */
+ s->async->events |= COMEDI_CB_EOA;
+ return false;
}
- if (err) {
- printk
- ("comedi%d: pcl812: (%s at 0x%lx) "
- "A/D cmd IRQ without DRDY!\n",
- dev->minor, dev->board_name, dev->iobase);
- pcl812_ai_cancel(dev, s);
+ return true;
+}
+
+static void pcl812_handle_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int next_chan;
+
+ if (pcl812_ai_eoc(dev, s, NULL, 0)) {
+ dev_dbg(dev->class_dev, "A/D cmd IRQ without DRDY!\n");
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ return;
}
- comedi_buf_put(s->async,
- ((inb(dev->iobase + PCL812_AD_HI) << 8) |
- inb(dev->iobase + PCL812_AD_LO)) & mask);
+ comedi_buf_put(s, pcl812_ai_get_sample(dev, s));
/* Set up next channel. Added by abbotti 2010-01-20, but untested. */
next_chan = s->async->cur_chan + 1;
- if (next_chan >= devpriv->ai_n_chan)
+ if (next_chan >= cmd->chanlist_len)
next_chan = 0;
- if (devpriv->ai_chanlist[s->async->cur_chan] !=
- devpriv->ai_chanlist[next_chan])
- setup_range_channel(dev, s, devpriv->ai_chanlist[next_chan], 0);
-
- outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
-
- s->async->cur_chan = next_chan;
- if (next_chan == 0) { /* one scan done */
- devpriv->ai_act_scan++;
- if (!(devpriv->ai_neverending))
- /* all data sampled */
- if (devpriv->ai_act_scan >= devpriv->ai_scans) {
- pcl812_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- }
- }
+ if (cmd->chanlist[s->async->cur_chan] != cmd->chanlist[next_chan])
+ pcl812_ai_set_chan_range(dev, cmd->chanlist[next_chan], 0);
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ pcl812_ai_next_chan(dev, s);
}
-/*
-==============================================================================
-*/
static void transfer_from_dma_buf(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned short *ptr,
unsigned int bufptr, unsigned int len)
{
- struct pcl812_private *devpriv = dev->private;
unsigned int i;
- s->async->events = 0;
for (i = len; i; i--) {
- /* get one sample */
- comedi_buf_put(s->async, ptr[bufptr++]);
-
- s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
- s->async->cur_chan = 0;
- devpriv->ai_act_scan++;
- if (!devpriv->ai_neverending)
- /* all data sampled */
- if (devpriv->ai_act_scan >= devpriv->ai_scans) {
- pcl812_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- break;
- }
- }
- }
+ comedi_buf_put(s, ptr[bufptr++]);
- comedi_event(dev, s);
+ if (!pcl812_ai_next_chan(dev, s))
+ break;
+ }
}
-/*
-==============================================================================
-*/
-static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d)
+static void pcl812_handle_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- struct comedi_device *dev = d;
struct pcl812_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
- unsigned long dma_flags;
int len, bufptr;
unsigned short *ptr;
@@ -874,58 +914,36 @@ static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d)
len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) -
devpriv->ai_poll_ptr;
- devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
- disable_dma(devpriv->dma);
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- dma_flags = claim_dma_lock();
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
- if (devpriv->ai_eos) {
- set_dma_count(devpriv->dma,
- devpriv->dmabytestomove[devpriv->next_dma_buf]);
- } else {
- if (devpriv->dma_runs_to_end) {
- set_dma_count(devpriv->dma,
- devpriv->dmabytestomove[devpriv->
- next_dma_buf]);
- } else {
- set_dma_count(devpriv->dma, devpriv->last_dma_run);
- }
- devpriv->dma_runs_to_end--;
- }
- release_dma_lock(dma_flags);
- enable_dma(devpriv->dma);
-
- outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
+ pcl812_ai_setup_next_dma(dev, s);
bufptr = devpriv->ai_poll_ptr;
devpriv->ai_poll_ptr = 0;
transfer_from_dma_buf(dev, s, ptr, bufptr, len);
-
- return IRQ_HANDLED;
}
-/*
-==============================================================================
-*/
-static irqreturn_t interrupt_pcl812(int irq, void *d)
+static irqreturn_t pcl812_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
+ struct comedi_subdevice *s = dev->read_subdev;
struct pcl812_private *devpriv = dev->private;
if (!dev->attached) {
- comedi_error(dev, "spurious interrupt");
+ pcl812_ai_clear_eoc(dev);
return IRQ_HANDLED;
}
+
if (devpriv->ai_dma)
- return interrupt_pcl812_ai_dma(irq, d);
+ pcl812_handle_dma(dev, s);
else
- return interrupt_pcl812_ai_int(irq, d);
+ pcl812_handle_eoc(dev, s);
+
+ pcl812_ai_clear_eoc(dev);
+
+ cfc_handle_events(dev, s);
+ return IRQ_HANDLED;
}
-/*
-==============================================================================
-*/
static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct pcl812_private *devpriv = dev->private;
@@ -970,221 +988,308 @@ static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
return s->async->buf_write_count - s->async->buf_read_count;
}
-/*
-==============================================================================
-*/
-static void setup_range_channel(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int rangechan, char wait)
+static int pcl812_ai_cancel(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct pcl812_private *devpriv = dev->private;
- unsigned char chan_reg = CR_CHAN(rangechan); /* normal board */
- /* gain index */
- unsigned char gain_reg = CR_RANGE(rangechan) +
- devpriv->range_correction;
- if ((chan_reg == devpriv->old_chan_reg)
- && (gain_reg == devpriv->old_gain_reg))
- return; /* we can return, no change */
+ if (devpriv->ai_dma)
+ disable_dma(devpriv->dma);
- devpriv->old_chan_reg = chan_reg;
- devpriv->old_gain_reg = gain_reg;
+ outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG,
+ dev->iobase + PCL812_CTRL_REG);
+ pcl812_start_pacer(dev, false);
+ pcl812_ai_clear_eoc(dev);
+ return 0;
+}
- if (devpriv->use_MPC) {
- if (devpriv->use_diff) {
- chan_reg = chan_reg | 0x30; /* DIFF inputs */
- } else {
- if (chan_reg & 0x80)
- /* SE inputs 8-15 */
- chan_reg = chan_reg | 0x20;
- else
- /* SE inputs 0-7 */
- chan_reg = chan_reg | 0x10;
- }
- }
+static int pcl812_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct pcl812_private *devpriv = dev->private;
+ int ret = 0;
+ int i;
- outb(chan_reg, dev->iobase + PCL812_MUX); /* select channel */
- outb(gain_reg, dev->iobase + PCL812_GAIN); /* select gain */
+ outb(devpriv->mode_reg_int | PCL812_CTRL_SOFT_TRIG,
+ dev->iobase + PCL812_CTRL_REG);
+ pcl812_ai_set_chan_range(dev, insn->chanspec, 1);
- if (wait)
- /*
- * XXX this depends on selected range and can be very long for
- * some high gain ranges!
- */
- udelay(devpriv->max_812_ai_mode0_rangewait);
+ for (i = 0; i < insn->n; i++) {
+ pcl812_ai_clear_eoc(dev);
+ pcl812_ai_soft_trig(dev);
+
+ ret = comedi_timeout(dev, s, insn, pcl812_ai_eoc, 0);
+ if (ret)
+ break;
+
+ data[i] = pcl812_ai_get_sample(dev, s);
+ }
+ outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG,
+ dev->iobase + PCL812_CTRL_REG);
+ pcl812_ai_clear_eoc(dev);
+
+ return ret ? ret : insn->n;
}
-/*
-==============================================================================
-*/
-static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2)
+static int pcl812_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- outb(0xb4, dev->iobase + PCL812_CTRCTL);
- outb(0x74, dev->iobase + PCL812_CTRCTL);
- udelay(1);
+ struct pcl812_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
- if (mode == 1) {
- outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2);
- outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2);
- outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1);
- outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1);
+ for (i = 0; i < insn->n; i++) {
+ outb((data[i] & 0xff),
+ dev->iobase + PCL812_AO_LSB_REG(chan));
+ outb((data[i] >> 8) & 0x0f,
+ dev->iobase + PCL812_AO_MSB_REG(chan));
+ devpriv->ao_readback[chan] = data[i];
}
+
+ return insn->n;
}
-/*
-==============================================================================
-*/
-static int pcl812_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int pcl812_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct pcl812_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
- if (devpriv->ai_dma)
- disable_dma(devpriv->dma);
- outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
- /* Stop A/D */
- outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
- start_pacer(dev, -1, 0, 0); /* stop 8254 */
- outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */
- return 0;
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
+
+ return insn->n;
+}
+
+static int pcl812_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ data[1] = inb(dev->iobase + PCL812_DI_LSB_REG) |
+ (inb(dev->iobase + PCL812_DI_MSB_REG) << 8);
+
+ return insn->n;
+}
+
+static int pcl812_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (comedi_dio_update_state(s, data)) {
+ outb(s->state & 0xff, dev->iobase + PCL812_DO_LSB_REG);
+ outb((s->state >> 8), dev->iobase + PCL812_DO_MSB_REG);
+ }
+
+ data[1] = s->state;
+
+ return insn->n;
}
-/*
-==============================================================================
-*/
static void pcl812_reset(struct comedi_device *dev)
{
const struct pcl812_board *board = comedi_board(dev);
struct pcl812_private *devpriv = dev->private;
+ unsigned int chan;
+
+ /* disable analog input trigger */
+ outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG,
+ dev->iobase + PCL812_CTRL_REG);
+ pcl812_ai_clear_eoc(dev);
+
+ /* stop pacer */
+ if (board->IRQbits)
+ pcl812_start_pacer(dev, false);
+
+ /*
+ * Invalidate last_ai_chanspec then set analog input to
+ * known channel/range.
+ */
+ devpriv->last_ai_chanspec = CR_PACK(16, 0, 0);
+ pcl812_ai_set_chan_range(dev, CR_PACK(0, 0, 0), 0);
+
+ /* set analog output channels to 0V */
+ for (chan = 0; chan < board->n_aochan; chan++) {
+ outb(0, dev->iobase + PCL812_AO_LSB_REG(chan));
+ outb(0, dev->iobase + PCL812_AO_MSB_REG(chan));
+ }
+
+ /* set all digital outputs low */
+ if (board->has_dio) {
+ outb(0, dev->iobase + PCL812_DO_MSB_REG);
+ outb(0, dev->iobase + PCL812_DO_LSB_REG);
+ }
+}
+
+static void pcl812_set_ai_range_table(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_devconfig *it)
+{
+ const struct pcl812_board *board = comedi_board(dev);
+ struct pcl812_private *devpriv = dev->private;
- outb(0, dev->iobase + PCL812_MUX);
- outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN);
- devpriv->old_chan_reg = -1; /* invalidate chain/gain memory */
- devpriv->old_gain_reg = -1;
+ /* default to the range table from the boardinfo */
+ s->range_table = board->rangelist_ai;
+ /* now check the user config option based on the boardtype */
switch (board->board_type) {
case boardPCL812PG:
+ if (it->options[4] == 1)
+ s->range_table = &range_pcl812pg2_ai;
+ break;
case boardPCL812:
- case boardACL8112:
- case boardACL8216:
- outb(0, dev->iobase + PCL812_DA2_LO);
- outb(0, dev->iobase + PCL812_DA2_HI);
- case boardA821:
- outb(0, dev->iobase + PCL812_DA1_LO);
- outb(0, dev->iobase + PCL812_DA1_HI);
- start_pacer(dev, -1, 0, 0); /* stop 8254 */
- outb(0, dev->iobase + PCL812_DO_HI);
- outb(0, dev->iobase + PCL812_DO_LO);
- outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
- outb(0, dev->iobase + PCL812_CLRINT);
+ switch (it->options[4]) {
+ case 0:
+ s->range_table = &range_bipolar10;
+ break;
+ case 1:
+ s->range_table = &range_bipolar5;
+ break;
+ case 2:
+ s->range_table = &range_bipolar2_5;
+ break;
+ case 3:
+ s->range_table = &range812_bipolar1_25;
+ break;
+ case 4:
+ s->range_table = &range812_bipolar0_625;
+ break;
+ case 5:
+ s->range_table = &range812_bipolar0_3125;
+ break;
+ default:
+ s->range_table = &range_bipolar10;
+ break;
+ }
break;
case boardPCL813B:
- case boardPCL813:
+ if (it->options[1] == 1)
+ s->range_table = &range_pcl813b2_ai;
+ break;
case boardISO813:
+ switch (it->options[1]) {
+ case 0:
+ s->range_table = &range_iso813_1_ai;
+ break;
+ case 1:
+ s->range_table = &range_iso813_1_2_ai;
+ break;
+ case 2:
+ s->range_table = &range_iso813_2_ai;
+ devpriv->range_correction = 1;
+ break;
+ case 3:
+ s->range_table = &range_iso813_2_2_ai;
+ devpriv->range_correction = 1;
+ break;
+ default:
+ s->range_table = &range_iso813_1_ai;
+ break;
+ }
+ break;
case boardACL8113:
- udelay(5);
+ switch (it->options[1]) {
+ case 0:
+ s->range_table = &range_acl8113_1_ai;
+ break;
+ case 1:
+ s->range_table = &range_acl8113_1_2_ai;
+ break;
+ case 2:
+ s->range_table = &range_acl8113_2_ai;
+ devpriv->range_correction = 1;
+ break;
+ case 3:
+ s->range_table = &range_acl8113_2_2_ai;
+ devpriv->range_correction = 1;
+ break;
+ default:
+ s->range_table = &range_acl8113_1_ai;
+ break;
+ }
break;
}
- udelay(5);
}
static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl812_board *board = comedi_board(dev);
struct pcl812_private *devpriv;
- int ret, subdev;
- unsigned int irq;
- unsigned int dma;
- unsigned long pages;
struct comedi_subdevice *s;
int n_subdevices;
-
- ret = comedi_request_region(dev, it->options[0], board->io_range);
- if (ret)
- return ret;
+ int subdev;
+ int ret;
+ int i;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- irq = 0;
- if (board->IRQbits != 0) { /* board support IRQ */
- irq = it->options[1];
- if (irq) { /* we want to use IRQ */
- if (((1 << irq) & board->IRQbits) == 0) {
- printk
- (", IRQ %u is out of allowed range, "
- "DISABLING IT", irq);
- irq = 0; /* Bad IRQ */
- } else {
- if (request_irq(irq, interrupt_pcl812, 0,
- dev->board_name, dev)) {
- printk
- (", unable to allocate IRQ %u, "
- "DISABLING IT", irq);
- irq = 0; /* Can't use IRQ */
- } else {
- printk(KERN_INFO ", irq=%u", irq);
- }
- }
- }
+ ret = comedi_request_region(dev, it->options[0], 0x10);
+ if (ret)
+ return ret;
+
+ if ((1 << it->options[1]) & board->IRQbits) {
+ ret = request_irq(it->options[1], pcl812_interrupt, 0,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = it->options[1];
}
- dev->irq = irq;
-
- dma = 0;
- devpriv->dma = dma;
- if (!dev->irq)
- goto no_dma; /* if we haven't IRQ, we can't use DMA */
- if (board->DMAbits != 0) { /* board support DMA */
- dma = it->options[2];
- if (((1 << dma) & board->DMAbits) == 0) {
- printk(", DMA is out of allowed range, FAIL!\n");
- return -EINVAL; /* Bad DMA */
- }
- ret = request_dma(dma, dev->board_name);
+ /* we need an IRQ to do DMA on channel 3 or 1 */
+ if (dev->irq && board->has_dma &&
+ (it->options[2] == 3 || it->options[2] == 1)) {
+ ret = request_dma(it->options[2], dev->board_name);
if (ret) {
- printk(KERN_ERR ", unable to allocate DMA %u, FAIL!\n",
- dma);
- return -EBUSY; /* DMA isn't free */
- }
- devpriv->dma = dma;
- printk(KERN_INFO ", dma=%u", dma);
- pages = 1; /* we want 8KB */
- devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[0]) {
- printk(", unable to allocate DMA buffer, FAIL!\n");
- /*
- * maybe experiment with try_to_free_pages()
- * will help ....
- */
- return -EBUSY; /* no buffer :-( */
- }
- devpriv->dmapages[0] = pages;
- devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
- devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages);
- devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[1]) {
- printk(KERN_ERR ", unable to allocate DMA buffer, FAIL!\n");
+ dev_err(dev->class_dev,
+ "unable to request DMA channel %d\n",
+ it->options[2]);
return -EBUSY;
}
- devpriv->dmapages[1] = pages;
- devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
- devpriv->hwdmasize[1] = PAGE_SIZE * (1 << pages);
+ devpriv->dma = it->options[2];
+
+ devpriv->dmapages = 1; /* we want 8KB */
+ devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
+
+ for (i = 0; i < 2; i++) {
+ unsigned long dmabuf;
+
+ dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
+ if (!dmabuf)
+ return -ENOMEM;
+
+ devpriv->dmabuf[i] = dmabuf;
+ devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
+ }
}
-no_dma:
- n_subdevices = 0;
- if (board->n_aichan > 0)
- n_subdevices++;
+ /* differential analog inputs? */
+ switch (board->board_type) {
+ case boardA821:
+ if (it->options[2] == 1)
+ devpriv->use_diff = 1;
+ break;
+ case boardACL8112:
+ case boardACL8216:
+ if (it->options[4] == 1)
+ devpriv->use_diff = 1;
+ break;
+ }
+
+ n_subdevices = 1; /* all boardtypes have analog inputs */
if (board->n_aochan > 0)
n_subdevices++;
- if (board->n_dichan > 0)
- n_subdevices++;
- if (board->n_dochan > 0)
- n_subdevices++;
+ if (board->has_dio)
+ n_subdevices += 2;
ret = comedi_alloc_subdevices(dev, n_subdevices);
if (ret)
@@ -1192,159 +1297,47 @@ no_dma:
subdev = 0;
- /* analog input */
- if (board->n_aichan > 0) {
- s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE;
- switch (board->board_type) {
- case boardA821:
- if (it->options[2] == 1) {
- s->n_chan = board->n_aichan_diff;
- s->subdev_flags |= SDF_DIFF;
- devpriv->use_diff = 1;
- } else {
- s->n_chan = board->n_aichan;
- s->subdev_flags |= SDF_GROUND;
- }
- break;
- case boardACL8112:
- case boardACL8216:
- if (it->options[4] == 1) {
- s->n_chan = board->n_aichan_diff;
- s->subdev_flags |= SDF_DIFF;
- devpriv->use_diff = 1;
- } else {
- s->n_chan = board->n_aichan;
- s->subdev_flags |= SDF_GROUND;
- }
- break;
- default:
- s->n_chan = board->n_aichan;
- s->subdev_flags |= SDF_GROUND;
- break;
- }
- s->maxdata = board->ai_maxdata;
- s->len_chanlist = MAX_CHANLIST_LEN;
- s->range_table = board->rangelist_ai;
- if (board->board_type == boardACL8216)
- s->insn_read = acl8216_ai_insn_read;
- else
- s->insn_read = pcl812_ai_insn_read;
-
- devpriv->use_MPC = board->haveMPC508;
- s->cancel = pcl812_ai_cancel;
- if (dev->irq) {
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->do_cmdtest = pcl812_ai_cmdtest;
- s->do_cmd = pcl812_ai_cmd;
- s->poll = pcl812_ai_poll;
- }
- switch (board->board_type) {
- case boardPCL812PG:
- if (it->options[4] == 1)
- s->range_table = &range_pcl812pg2_ai;
- break;
- case boardPCL812:
- switch (it->options[4]) {
- case 0:
- s->range_table = &range_bipolar10;
- break;
- case 1:
- s->range_table = &range_bipolar5;
- break;
- case 2:
- s->range_table = &range_bipolar2_5;
- break;
- case 3:
- s->range_table = &range812_bipolar1_25;
- break;
- case 4:
- s->range_table = &range812_bipolar0_625;
- break;
- case 5:
- s->range_table = &range812_bipolar0_3125;
- break;
- default:
- s->range_table = &range_bipolar10;
- break;
- printk
- (", incorrect range number %d, changing "
- "to 0 (+/-10V)", it->options[4]);
- break;
- }
- break;
- break;
- case boardPCL813B:
- if (it->options[1] == 1)
- s->range_table = &range_pcl813b2_ai;
- break;
- case boardISO813:
- switch (it->options[1]) {
- case 0:
- s->range_table = &range_iso813_1_ai;
- break;
- case 1:
- s->range_table = &range_iso813_1_2_ai;
- break;
- case 2:
- s->range_table = &range_iso813_2_ai;
- devpriv->range_correction = 1;
- break;
- case 3:
- s->range_table = &range_iso813_2_2_ai;
- devpriv->range_correction = 1;
- break;
- default:
- s->range_table = &range_iso813_1_ai;
- break;
- printk
- (", incorrect range number %d, "
- "changing to 0 ", it->options[1]);
- break;
- }
- break;
- case boardACL8113:
- switch (it->options[1]) {
- case 0:
- s->range_table = &range_acl8113_1_ai;
- break;
- case 1:
- s->range_table = &range_acl8113_1_2_ai;
- break;
- case 2:
- s->range_table = &range_acl8113_2_ai;
- devpriv->range_correction = 1;
- break;
- case 3:
- s->range_table = &range_acl8113_2_2_ai;
- devpriv->range_correction = 1;
- break;
- default:
- s->range_table = &range_acl8113_1_ai;
- break;
- printk
- (", incorrect range number %d, "
- "changing to 0 ", it->options[1]);
- break;
- }
- break;
- }
- subdev++;
+ /* Analog Input subdevice */
+ s = &dev->subdevices[subdev];
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE;
+ if (devpriv->use_diff) {
+ s->subdev_flags |= SDF_DIFF;
+ s->n_chan = board->n_aichan / 2;
+ } else {
+ s->subdev_flags |= SDF_GROUND;
+ s->n_chan = board->n_aichan;
}
+ s->maxdata = board->has_16bit_ai ? 0xffff : 0x0fff;
+
+ pcl812_set_ai_range_table(dev, s, it);
+
+ s->insn_read = pcl812_ai_insn_read;
+
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = MAX_CHANLIST_LEN;
+ s->do_cmdtest = pcl812_ai_cmdtest;
+ s->do_cmd = pcl812_ai_cmd;
+ s->poll = pcl812_ai_poll;
+ s->cancel = pcl812_ai_cancel;
+ }
+
+ devpriv->use_mpc508 = board->has_mpc508_mux;
+
+ subdev++;
/* analog output */
if (board->n_aochan > 0) {
s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
- s->n_chan = board->n_aochan;
- s->maxdata = 0xfff;
- s->len_chanlist = 1;
- s->range_table = board->rangelist_ao;
- s->insn_read = pcl812_ao_insn_read;
- s->insn_write = pcl812_ao_insn_write;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
+ s->n_chan = board->n_aochan;
+ s->maxdata = 0xfff;
+ s->range_table = &range_unipolar5;
+ s->insn_read = pcl812_ao_insn_read;
+ s->insn_write = pcl812_ao_insn_write;
switch (board->board_type) {
case boardA821:
if (it->options[3] == 1)
@@ -1363,35 +1356,30 @@ no_dma:
subdev++;
}
- /* digital input */
- if (board->n_dichan > 0) {
+ if (board->has_dio) {
+ /* Digital Input subdevice */
s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = board->n_dichan;
- s->maxdata = 1;
- s->len_chanlist = board->n_dichan;
- s->range_table = &range_digital;
- s->insn_bits = pcl812_di_insn_bits;
+ 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 = pcl812_di_insn_bits;
subdev++;
- }
- /* digital output */
- if (board->n_dochan > 0) {
+ /* Digital Output subdevice */
s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = board->n_dochan;
- s->maxdata = 1;
- s->len_chanlist = board->n_dochan;
- s->range_table = &range_digital;
- s->insn_bits = pcl812_do_insn_bits;
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcl812_do_insn_bits;
subdev++;
}
switch (board->board_type) {
case boardACL8216:
- devpriv->ai_is16b = 1;
case boardPCL812PG:
case boardPCL812:
case boardACL8112:
@@ -1402,7 +1390,7 @@ no_dma:
break;
case boardA821:
devpriv->max_812_ai_mode0_rangewait = 1;
- devpriv->mode_reg_int = (irq << 4) & 0xf0;
+ devpriv->mode_reg_int = (dev->irq << 4) & 0xf0;
break;
case boardPCL813B:
case boardPCL813:
@@ -1413,9 +1401,6 @@ no_dma:
break;
}
- printk(KERN_INFO "\n");
- devpriv->valid = 1;
-
pcl812_reset(dev);
return 0;
@@ -1427,72 +1412,15 @@ static void pcl812_detach(struct comedi_device *dev)
if (devpriv) {
if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
+ free_pages(devpriv->dmabuf[0], devpriv->dmapages);
if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
+ free_pages(devpriv->dmabuf[1], devpriv->dmapages);
if (devpriv->dma)
free_dma(devpriv->dma);
}
comedi_legacy_detach(dev);
}
-static const struct pcl812_board boardtypes[] = {
- {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff,
- 33000, I8254_OSC_BASE_2MHZ, &range_bipolar10, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
- 33000, I8254_OSC_BASE_2MHZ, &range_pcl812pg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_pcl812pg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
- {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
- {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b_ai, &range_unipolar5,
- 0x000c, 0x00, PCLx1x_IORANGE, 0},
- {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b_ai, NULL,
- 0x000c, 0x00, PCLx1x_IORANGE, 0},
- {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_a821pgh_ai, &range_unipolar5,
- 0x000c, 0x00, PCLx1x_IORANGE, 0},
- {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 8000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 8000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_pcl813b_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_pcl813b_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_acl8113_1_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_iso813_1_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
- 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b2_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
- {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
- 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b2_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
-};
-
static struct comedi_driver pcl812_driver = {
.driver_name = "pcl812",
.module = THIS_MODULE,
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index ab9d2bd26a2..d9ca7fe16c9 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -44,394 +44,331 @@ Configuration Options:
#include "comedi_fc.h"
#include "8253.h"
-#define DEBUG(x) x
-
-/* boards constants */
-/* IO space len */
-#define PCLx1x_RANGE 16
-
-/* #define outb(x,y) printk("OUTB(%x, 200+%d)\n", x,y-0x200); outb(x,y) */
-
-/* INTEL 8254 counters */
-#define PCL816_CTR0 4
-#define PCL816_CTR1 5
-#define PCL816_CTR2 6
-/* R: counter read-back register W: counter control */
-#define PCL816_CTRCTL 7
-
-/* R: A/D high byte W: A/D range control */
-#define PCL816_RANGE 9
-/* W: clear INT request */
-#define PCL816_CLRINT 10
-/* R: next mux scan channel W: mux scan channel & range control pointer */
-#define PCL816_MUX 11
-/* R/W: operation control register */
-#define PCL816_CONTROL 12
-
-/* R: return status byte W: set DMA/IRQ */
-#define PCL816_STATUS 13
-#define PCL816_STATUS_DRDY_MASK 0x80
-
-/* R: low byte of A/D W: soft A/D trigger */
-#define PCL816_AD_LO 8
-/* R: high byte of A/D W: A/D range control */
-#define PCL816_AD_HI 9
-
-/* type of interrupt handler */
-#define INT_TYPE_AI1_INT 1
-#define INT_TYPE_AI1_DMA 2
-#define INT_TYPE_AI3_INT 4
-#define INT_TYPE_AI3_DMA 5
+/*
+ * Register I/O map
+ */
+#define PCL816_DO_DI_LSB_REG 0x00
+#define PCL816_DO_DI_MSB_REG 0x01
+#define PCL816_TIMER_BASE 0x04
+#define PCL816_AI_LSB_REG 0x08
+#define PCL816_AI_MSB_REG 0x09
+#define PCL816_RANGE_REG 0x09
+#define PCL816_CLRINT_REG 0x0a
+#define PCL816_MUX_REG 0x0b
+#define PCL816_MUX_SCAN(_first, _last) (((_last) << 4) | (_first))
+#define PCL816_CTRL_REG 0x0c
+#define PCL816_CTRL_DISABLE_TRIG (0 << 0)
+#define PCL816_CTRL_SOFT_TRIG (1 << 0)
+#define PCL816_CTRL_PACER_TRIG (1 << 1)
+#define PCL816_CTRL_EXT_TRIG (1 << 2)
+#define PCL816_CTRL_POE (1 << 3)
+#define PCL816_CTRL_DMAEN (1 << 4)
+#define PCL816_CTRL_INTEN (1 << 5)
+#define PCL816_CTRL_DMASRC_SLOT0 (0 << 6)
+#define PCL816_CTRL_DMASRC_SLOT1 (1 << 6)
+#define PCL816_CTRL_DMASRC_SLOT2 (2 << 6)
+#define PCL816_STATUS_REG 0x0d
+#define PCL816_STATUS_NEXT_CHAN_MASK (0xf << 0)
+#define PCL816_STATUS_INTSRC_MASK (3 << 4)
+#define PCL816_STATUS_INTSRC_SLOT0 (0 << 4)
+#define PCL816_STATUS_INTSRC_SLOT1 (1 << 4)
+#define PCL816_STATUS_INTSRC_SLOT2 (2 << 4)
+#define PCL816_STATUS_INTSRC_DMA (3 << 4)
+#define PCL816_STATUS_INTACT (1 << 6)
+#define PCL816_STATUS_DRDY (1 << 7)
#define MAGIC_DMA_WORD 0x5a5a
-static const struct comedi_lrange range_pcl816 = { 8, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25),
- }
+static const struct comedi_lrange range_pcl816 = {
+ 8, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
};
struct pcl816_board {
+ const char *name;
+ int ai_maxdata;
+ int ao_maxdata;
+ int ai_chanlist;
+};
- const char *name; /* board name */
- int n_ranges; /* len of range list */
- int n_aichan; /* num of A/D chans in diferencial mode */
- unsigned int ai_ns_min; /* minimal allowed delay between samples (in ns) */
- int n_aochan; /* num of D/A chans */
- int n_dichan; /* num of DI chans */
- int n_dochan; /* num of DO chans */
- const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
- const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
- unsigned int io_range; /* len of IO space */
- unsigned int IRQbits; /* allowed interrupts */
- unsigned int DMAbits; /* allowed DMA chans */
- int ai_maxdata; /* maxdata for A/D */
- int ao_maxdata; /* maxdata for D/A */
- int ai_chanlist; /* allowed len of channel list A/D */
- int ao_chanlist; /* allowed len of channel list D/A */
- int i8254_osc_base; /* 1/frequency of on board oscilator in ns */
+static const struct pcl816_board boardtypes[] = {
+ {
+ .name = "pcl816",
+ .ai_maxdata = 0xffff,
+ .ao_maxdata = 0xffff,
+ .ai_chanlist = 1024,
+ }, {
+ .name = "pcl814b",
+ .ai_maxdata = 0x3fff,
+ .ao_maxdata = 0x3fff,
+ .ai_chanlist = 1024,
+ },
};
struct pcl816_private {
-
unsigned int dma; /* used DMA, 0=don't use DMA */
+ unsigned int dmapages;
+ unsigned int hwdmasize;
unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
- unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
- unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
- unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
int next_dma_buf; /* which DMA buffer will be used next round */
long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
-
- unsigned int ai_scans; /* len of scanlist */
- unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */
- int irq_free; /* 1=have allocated IRQ */
- int irq_blocked; /* 1=IRQ now uses any subdev */
- int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */
- int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
- struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
int ai_act_scan; /* how many scans we finished */
- unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */
- unsigned int ai_act_chanlist_len; /* how long is actual MUX list */
- unsigned int ai_act_chanlist_pos; /* actual position in MUX list */
- unsigned int ai_n_chan; /* how many channels per scan */
unsigned int ai_poll_ptr; /* how many sampes transfer poll */
- struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
+ unsigned int divisor1;
+ unsigned int divisor2;
+ unsigned int ai_cmd_running:1;
+ unsigned int ai_cmd_canceled:1;
};
-/*
-==============================================================================
-*/
static int check_channel_list(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int *chanlist, unsigned int chanlen);
-static void setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int seglen);
-static int pcl816_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2);
-
-static int pcl816_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-/*
-==============================================================================
- ANALOG INPUT MODE0, 816 cards, slow version
-*/
-static int pcl816_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl816_start_pacer(struct comedi_device *dev, bool load_counters)
{
- int n;
- int timeout;
-
- DPRINTK("mode 0 analog input\n");
- /* software trigger, DMA and INT off */
- outb(0, dev->iobase + PCL816_CONTROL);
- /* clear INT (conversion end) flag */
- outb(0, dev->iobase + PCL816_CLRINT);
-
- /* Set the input channel */
- outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX);
- /* select gain */
- outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE);
-
- for (n = 0; n < insn->n; n++) {
-
- outb(0, dev->iobase + PCL816_AD_LO); /* start conversion */
-
- timeout = 100;
- while (timeout--) {
- if (!(inb(dev->iobase + PCL816_STATUS) &
- PCL816_STATUS_DRDY_MASK)) {
- /* return read value */
- data[n] =
- ((inb(dev->iobase +
- PCL816_AD_HI) << 8) |
- (inb(dev->iobase + PCL816_AD_LO)));
- /* clear INT (conversion end) flag */
- outb(0, dev->iobase + PCL816_CLRINT);
- break;
- }
- udelay(1);
- }
- /* Return timeout error */
- if (!timeout) {
- comedi_error(dev, "A/D insn timeout\n");
- data[0] = 0;
- /* clear INT (conversion end) flag */
- outb(0, dev->iobase + PCL816_CLRINT);
- return -EIO;
- }
+ struct pcl816_private *devpriv = dev->private;
+ unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE;
+ i8254_set_mode(timer_base, 0, 0, I8254_MODE1 | I8254_BINARY);
+ i8254_write(timer_base, 0, 0, 0x00ff);
+ udelay(1);
+
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ udelay(1);
+
+ if (load_counters) {
+ i8254_write(timer_base, 0, 2, devpriv->divisor2);
+ i8254_write(timer_base, 0, 1, devpriv->divisor1);
}
- return n;
}
-/*
-==============================================================================
- analog input interrupt mode 1 & 3, 818 cards
- one sample per interrupt version
-*/
-static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d)
+static void pcl816_ai_setup_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- struct comedi_device *dev = d;
struct pcl816_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
- unsigned char low, hi;
- int timeout = 50; /* wait max 50us */
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int dma_flags;
+ unsigned int bytes;
- while (timeout--) {
- if (!(inb(dev->iobase + PCL816_STATUS) &
- PCL816_STATUS_DRDY_MASK))
- break;
- udelay(1);
+ bytes = devpriv->hwdmasize;
+ if (cmd->stop_src == TRIG_COUNT) {
+ /* how many */
+ bytes = cmd->stop_arg * cfc_bytes_per_scan(s);
+
+ /* how many DMA pages we must fill */
+ devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize;
+
+ /* on last dma transfer must be moved */
+ devpriv->last_dma_run = bytes % devpriv->hwdmasize;
+ devpriv->dma_runs_to_end--;
+ if (devpriv->dma_runs_to_end >= 0)
+ bytes = devpriv->hwdmasize;
+ } else
+ devpriv->dma_runs_to_end = -1;
+
+ devpriv->next_dma_buf = 0;
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ dma_flags = claim_dma_lock();
+ clear_dma_ff(devpriv->dma);
+ set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
+ set_dma_count(devpriv->dma, bytes);
+ release_dma_lock(dma_flags);
+ enable_dma(devpriv->dma);
+}
+
+static void pcl816_ai_setup_next_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct pcl816_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned long dma_flags;
+
+ disable_dma(devpriv->dma);
+ if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) {
+ /* switch dma bufs */
+ devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ dma_flags = claim_dma_lock();
+ set_dma_addr(devpriv->dma,
+ devpriv->hwdmaptr[devpriv->next_dma_buf]);
+ if (devpriv->dma_runs_to_end)
+ set_dma_count(devpriv->dma, devpriv->hwdmasize);
+ else
+ set_dma_count(devpriv->dma, devpriv->last_dma_run);
+ release_dma_lock(dma_flags);
+ enable_dma(devpriv->dma);
}
- if (!timeout) { /* timeout, bail error */
- outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
- comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
- pcl816_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ devpriv->dma_runs_to_end--;
+}
+
+static void pcl816_ai_set_chan_range(struct comedi_device *dev,
+ unsigned int chan,
+ unsigned int range)
+{
+ outb(chan, dev->iobase + PCL816_MUX_REG);
+ outb(range, dev->iobase + PCL816_RANGE_REG);
+}
+
+static void pcl816_ai_set_chan_scan(struct comedi_device *dev,
+ unsigned int first_chan,
+ unsigned int last_chan)
+{
+ outb(PCL816_MUX_SCAN(first_chan, last_chan),
+ dev->iobase + PCL816_MUX_REG);
+}
+
+static void pcl816_ai_setup_chanlist(struct comedi_device *dev,
+ unsigned int *chanlist,
+ unsigned int seglen)
+{
+ unsigned int first_chan = CR_CHAN(chanlist[0]);
+ unsigned int last_chan;
+ unsigned int range;
+ unsigned int i;
+
+ /* store range list to card */
+ for (i = 0; i < seglen; i++) {
+ last_chan = CR_CHAN(chanlist[i]);
+ range = CR_RANGE(chanlist[i]);
+
+ pcl816_ai_set_chan_range(dev, last_chan, range);
}
- /* get the sample */
- low = inb(dev->iobase + PCL816_AD_LO);
- hi = inb(dev->iobase + PCL816_AD_HI);
+ udelay(1);
+
+ pcl816_ai_set_chan_scan(dev, first_chan, last_chan);
+}
+
+static void pcl816_ai_clear_eoc(struct comedi_device *dev)
+{
+ /* writing any value clears the interrupt request */
+ outb(0, dev->iobase + PCL816_CLRINT_REG);
+}
+
+static void pcl816_ai_soft_trig(struct comedi_device *dev)
+{
+ /* writing any value triggers a software conversion */
+ outb(0, dev->iobase + PCL816_AI_LSB_REG);
+}
- comedi_buf_put(s->async, (hi << 8) | low);
+static unsigned int pcl816_ai_get_sample(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ unsigned int val;
- outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
+ val = inb(dev->iobase + PCL816_AI_MSB_REG) << 8;
+ val |= inb(dev->iobase + PCL816_AI_LSB_REG);
- if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len)
- devpriv->ai_act_chanlist_pos = 0;
+ return val & s->maxdata;
+}
+
+static int pcl816_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + PCL816_STATUS_REG);
+ if ((status & PCL816_STATUS_DRDY) == 0)
+ return 0;
+ return -EBUSY;
+}
+
+static bool pcl816_ai_next_chan(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct pcl816_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+
+ s->async->events |= COMEDI_CB_BLOCK;
s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
+ if (s->async->cur_chan >= cmd->chanlist_len) {
s->async->cur_chan = 0;
devpriv->ai_act_scan++;
+ s->async->events |= COMEDI_CB_EOS;
}
- if (!devpriv->ai_neverending)
- /* all data sampled */
- if (devpriv->ai_act_scan >= devpriv->ai_scans) {
- /* all data sampled */
- pcl816_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- }
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ if (cmd->stop_src == TRIG_COUNT &&
+ devpriv->ai_act_scan >= cmd->stop_arg) {
+ /* all data sampled */
+ s->async->events |= COMEDI_CB_EOA;
+ return false;
+ }
+
+ return true;
}
-/*
-==============================================================================
- analog input dma mode 1 & 3, 816 cards
-*/
static void transfer_from_dma_buf(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned short *ptr,
unsigned int bufptr, unsigned int len)
{
- struct pcl816_private *devpriv = dev->private;
int i;
- s->async->events = 0;
-
for (i = 0; i < len; i++) {
+ comedi_buf_put(s, ptr[bufptr++]);
- comedi_buf_put(s->async, ptr[bufptr++]);
-
- if (++devpriv->ai_act_chanlist_pos >=
- devpriv->ai_act_chanlist_len) {
- devpriv->ai_act_chanlist_pos = 0;
- }
-
- s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
- s->async->cur_chan = 0;
- devpriv->ai_act_scan++;
- }
-
- if (!devpriv->ai_neverending)
- /* all data sampled */
- if (devpriv->ai_act_scan >= devpriv->ai_scans) {
- pcl816_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- s->async->events |= COMEDI_CB_BLOCK;
- break;
- }
+ if (!pcl816_ai_next_chan(dev, s))
+ return;
}
-
- comedi_event(dev, s);
}
-static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d)
+static irqreturn_t pcl816_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
+ struct comedi_subdevice *s = dev->read_subdev;
struct pcl816_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
- int len, bufptr, this_dma_buf;
- unsigned long dma_flags;
unsigned short *ptr;
+ unsigned int bufptr;
+ unsigned int len;
- disable_dma(devpriv->dma);
- this_dma_buf = devpriv->next_dma_buf;
-
- /* switch dma bufs */
- if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) {
+ if (!dev->attached || !devpriv->ai_cmd_running) {
+ pcl816_ai_clear_eoc(dev);
+ return IRQ_HANDLED;
+ }
- devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- dma_flags = claim_dma_lock();
-/* clear_dma_ff (devpriv->dma); */
- set_dma_addr(devpriv->dma,
- devpriv->hwdmaptr[devpriv->next_dma_buf]);
- if (devpriv->dma_runs_to_end) {
- set_dma_count(devpriv->dma,
- devpriv->hwdmasize[devpriv->
- next_dma_buf]);
- } else {
- set_dma_count(devpriv->dma, devpriv->last_dma_run);
- }
- release_dma_lock(dma_flags);
- enable_dma(devpriv->dma);
+ if (devpriv->ai_cmd_canceled) {
+ devpriv->ai_cmd_canceled = 0;
+ pcl816_ai_clear_eoc(dev);
+ return IRQ_HANDLED;
}
- devpriv->dma_runs_to_end--;
- outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
+ ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf];
- ptr = (unsigned short *)devpriv->dmabuf[this_dma_buf];
+ pcl816_ai_setup_next_dma(dev, s);
- len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr;
+ len = (devpriv->hwdmasize >> 1) - devpriv->ai_poll_ptr;
bufptr = devpriv->ai_poll_ptr;
devpriv->ai_poll_ptr = 0;
transfer_from_dma_buf(dev, s, ptr, bufptr, len);
- return IRQ_HANDLED;
-}
-/*
-==============================================================================
- INT procedure
-*/
-static irqreturn_t interrupt_pcl816(int irq, void *d)
-{
- struct comedi_device *dev = d;
- struct pcl816_private *devpriv = dev->private;
-
- DPRINTK("<I>");
-
- if (!dev->attached) {
- comedi_error(dev, "premature interrupt");
- return IRQ_HANDLED;
- }
-
- switch (devpriv->int816_mode) {
- case INT_TYPE_AI1_DMA:
- case INT_TYPE_AI3_DMA:
- return interrupt_pcl816_ai_mode13_dma(irq, d);
- case INT_TYPE_AI1_INT:
- case INT_TYPE_AI3_INT:
- return interrupt_pcl816_ai_mode13_int(irq, d);
- }
-
- outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
- if (!dev->irq || !devpriv->irq_free || !devpriv->irq_blocked ||
- !devpriv->int816_mode) {
- if (devpriv->irq_was_now_closed) {
- devpriv->irq_was_now_closed = 0;
- /* comedi_error(dev,"last IRQ.."); */
- return IRQ_HANDLED;
- }
- comedi_error(dev, "bad IRQ!");
- return IRQ_NONE;
- }
- comedi_error(dev, "IRQ from unknown source!");
- return IRQ_NONE;
-}
+ pcl816_ai_clear_eoc(dev);
-/*
-==============================================================================
- COMMAND MODE
-*/
-static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd)
-{
- printk(KERN_INFO "pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e,
- cmd->start_src, cmd->scan_begin_src, cmd->convert_src);
- printk(KERN_INFO "pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e,
- cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg);
- printk(KERN_INFO "pcl816 e=%d stopsrc=%x scanend=%x\n", e,
- cmd->stop_src, cmd->scan_end_src);
- printk(KERN_INFO "pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n",
- e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len);
+ cfc_handle_events(dev, s);
+ return IRQ_HANDLED;
}
-/*
-==============================================================================
-*/
static int pcl816_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
- const struct pcl816_board *board = comedi_board(dev);
+ struct pcl816_private *devpriv = dev->private;
int err = 0;
- int tmp, divisor1 = 0, divisor2 = 0;
-
- DEBUG(printk(KERN_INFO "pcl816 pcl812_ai_cmdtest\n");
- pcl816_cmdtest_out(-1, cmd);
- );
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -461,8 +398,7 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
if (cmd->convert_src == TRIG_TIMER)
- err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
- board->ai_ns_min);
+ err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
else /* TRIG_EXT */
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
@@ -479,14 +415,12 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
- i8253_cascade_ns_to_timer(board->i8254_osc_base,
- &divisor1, &divisor2,
- &cmd->convert_arg, cmd->flags);
- if (cmd->convert_arg < board->ai_ns_min)
- cmd->convert_arg = board->ai_ns_min;
- if (tmp != cmd->convert_arg)
- err++;
+ arg = cmd->convert_arg;
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
+ &devpriv->divisor1,
+ &devpriv->divisor2,
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
}
if (err)
@@ -506,131 +440,41 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
- const struct pcl816_board *board = comedi_board(dev);
struct pcl816_private *devpriv = dev->private;
- unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq;
struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int ctrl;
unsigned int seglen;
- if (cmd->start_src != TRIG_NOW)
- return -EINVAL;
- if (cmd->scan_begin_src != TRIG_FOLLOW)
- return -EINVAL;
- if (cmd->scan_end_src != TRIG_COUNT)
- return -EINVAL;
- if (cmd->scan_end_arg != cmd->chanlist_len)
- return -EINVAL;
-/* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */
- if (devpriv->irq_blocked)
+ if (devpriv->ai_cmd_running)
return -EBUSY;
- if (cmd->convert_src == TRIG_TIMER) {
- if (cmd->convert_arg < board->ai_ns_min)
- cmd->convert_arg = board->ai_ns_min;
-
- i8253_cascade_ns_to_timer(board->i8254_osc_base,
- &divisor1, &divisor2,
- &cmd->convert_arg, cmd->flags);
-
- /* PCL816 crash if any divisor is set to 1 */
- if (divisor1 == 1) {
- divisor1 = 2;
- divisor2 /= 2;
- }
- if (divisor2 == 1) {
- divisor2 = 2;
- divisor1 /= 2;
- }
- }
-
- start_pacer(dev, -1, 0, 0); /* stop pacer */
+ pcl816_start_pacer(dev, false);
seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
if (seglen < 1)
return -EINVAL;
- setup_channel_list(dev, s, cmd->chanlist, seglen);
+ pcl816_ai_setup_chanlist(dev, cmd->chanlist, seglen);
udelay(1);
- devpriv->ai_n_chan = cmd->chanlist_len;
devpriv->ai_act_scan = 0;
s->async->cur_chan = 0;
- devpriv->irq_blocked = 1;
+ devpriv->ai_cmd_running = 1;
devpriv->ai_poll_ptr = 0;
- devpriv->irq_was_now_closed = 0;
-
- if (cmd->stop_src == TRIG_COUNT) {
- devpriv->ai_scans = cmd->stop_arg;
- devpriv->ai_neverending = 0;
- } else {
- devpriv->ai_scans = 0;
- devpriv->ai_neverending = 1;
- }
-
- /* don't we want wake up every scan? */
- if ((cmd->flags & TRIG_WAKE_EOS)) {
- printk(KERN_INFO
- "pl816: You wankt WAKE_EOS but I dont want handle it");
- /* devpriv->ai_eos=1; */
- /* if (devpriv->ai_n_chan==1) */
- /* devpriv->dma=0; // DMA is useless for this situation */
- }
-
- if (devpriv->dma) {
- bytes = devpriv->hwdmasize[0];
- if (!devpriv->ai_neverending) {
- /* how many */
- bytes = s->async->cmd.chanlist_len *
- s->async->cmd.chanlist_len *
- sizeof(short);
-
- /* how many DMA pages we must fill */
- devpriv->dma_runs_to_end = bytes /
- devpriv->hwdmasize[0];
-
- /* on last dma transfer must be moved */
- devpriv->last_dma_run = bytes % devpriv->hwdmasize[0];
- devpriv->dma_runs_to_end--;
- if (devpriv->dma_runs_to_end >= 0)
- bytes = devpriv->hwdmasize[0];
- } else
- devpriv->dma_runs_to_end = -1;
-
- devpriv->next_dma_buf = 0;
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- dma_flags = claim_dma_lock();
- clear_dma_ff(devpriv->dma);
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
- set_dma_count(devpriv->dma, bytes);
- release_dma_lock(dma_flags);
- enable_dma(devpriv->dma);
- }
-
- start_pacer(dev, 1, divisor1, divisor2);
- dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7);
-
- switch (cmd->convert_src) {
- case TRIG_TIMER:
- devpriv->int816_mode = INT_TYPE_AI1_DMA;
-
- /* Pacer+IRQ+DMA */
- outb(0x32, dev->iobase + PCL816_CONTROL);
+ devpriv->ai_cmd_canceled = 0;
- /* write irq and DMA to card */
- outb(dmairq, dev->iobase + PCL816_STATUS);
- break;
+ pcl816_ai_setup_dma(dev, s);
- default:
- devpriv->int816_mode = INT_TYPE_AI3_DMA;
+ pcl816_start_pacer(dev, true);
- /* Ext trig+IRQ+DMA */
- outb(0x34, dev->iobase + PCL816_CONTROL);
+ ctrl = PCL816_CTRL_INTEN | PCL816_CTRL_DMAEN | PCL816_CTRL_DMASRC_SLOT0;
+ if (cmd->convert_src == TRIG_TIMER)
+ ctrl |= PCL816_CTRL_PACER_TRIG;
+ else /* TRIG_EXT */
+ ctrl |= PCL816_CTRL_EXT_TRIG;
- /* write irq to card */
- outb(dmairq, dev->iobase + PCL816_STATUS);
- break;
- }
+ outb(ctrl, dev->iobase + PCL816_CTRL_REG);
+ outb((devpriv->dma << 4) | dev->irq, dev->iobase + PCL816_STATUS_REG);
- DPRINTK("pcl816 END: pcl812_ai_cmd()\n");
return 0;
}
@@ -640,9 +484,6 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
unsigned long flags;
unsigned int top1, top2, i;
- if (!devpriv->dma)
- return 0; /* poll is valid only for DMA transfer */
-
spin_lock_irqsave(&dev->spinlock, flags);
for (i = 0; i < 20; i++) {
@@ -657,7 +498,7 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
}
/* where is now DMA in buffer */
- top1 = devpriv->hwdmasize[0] - top1;
+ top1 = devpriv->hwdmasize - top1;
top1 >>= 1; /* sample position */
top2 = top1 - devpriv->ai_poll_ptr;
if (top2 < 1) { /* no new samples */
@@ -673,138 +514,34 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_poll_ptr = top1; /* new buffer position */
spin_unlock_irqrestore(&dev->spinlock, flags);
+ cfc_handle_events(dev, s);
+
return s->async->buf_write_count - s->async->buf_read_count;
}
-/*
-==============================================================================
- cancel any mode 1-4 AI
-*/
static int pcl816_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct pcl816_private *devpriv = dev->private;
-/* DEBUG(printk("pcl816_ai_cancel()\n");) */
-
- if (devpriv->irq_blocked > 0) {
- switch (devpriv->int816_mode) {
- case INT_TYPE_AI1_DMA:
- case INT_TYPE_AI3_DMA:
- disable_dma(devpriv->dma);
- case INT_TYPE_AI1_INT:
- case INT_TYPE_AI3_INT:
- outb(inb(dev->iobase + PCL816_CONTROL) & 0x73,
- dev->iobase + PCL816_CONTROL); /* Stop A/D */
- udelay(1);
- outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */
-
- /* Stop pacer */
- outb(0xb0, dev->iobase + PCL816_CTRCTL);
- outb(0x70, dev->iobase + PCL816_CTRCTL);
- outb(0, dev->iobase + PCL816_AD_LO);
- inb(dev->iobase + PCL816_AD_LO);
- inb(dev->iobase + PCL816_AD_HI);
-
- /* clear INT request */
- outb(0, dev->iobase + PCL816_CLRINT);
-
- /* Stop A/D */
- outb(0, dev->iobase + PCL816_CONTROL);
- devpriv->irq_blocked = 0;
- devpriv->irq_was_now_closed = devpriv->int816_mode;
- devpriv->int816_mode = 0;
- devpriv->last_int_sub = s;
-/* s->busy = 0; */
- break;
- }
- }
-
- DEBUG(printk("comedi: pcl816_ai_cancel() successful\n");)
- return 0;
-}
-
-/*
-==============================================================================
- chech for PCL816
-*/
-static int pcl816_check(unsigned long iobase)
-{
- outb(0x00, iobase + PCL816_MUX);
- udelay(1);
- if (inb(iobase + PCL816_MUX) != 0x00)
- return 1; /* there isn't card */
- outb(0x55, iobase + PCL816_MUX);
- udelay(1);
- if (inb(iobase + PCL816_MUX) != 0x55)
- return 1; /* there isn't card */
- outb(0x00, iobase + PCL816_MUX);
- udelay(1);
- outb(0x18, iobase + PCL816_CONTROL);
- udelay(1);
- if (inb(iobase + PCL816_CONTROL) != 0x18)
- return 1; /* there isn't card */
- return 0; /* ok, card exist */
-}
-
-/*
-==============================================================================
- reset whole PCL-816 cards
-*/
-static void pcl816_reset(struct comedi_device *dev)
-{
-/* outb (0, dev->iobase + PCL818_DA_LO); DAC=0V */
-/* outb (0, dev->iobase + PCL818_DA_HI); */
-/* udelay (1); */
-/* outb (0, dev->iobase + PCL818_DO_HI); DO=$0000 */
-/* outb (0, dev->iobase + PCL818_DO_LO); */
-/* udelay (1); */
- outb(0, dev->iobase + PCL816_CONTROL);
- outb(0, dev->iobase + PCL816_MUX);
- outb(0, dev->iobase + PCL816_CLRINT);
- outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */
- outb(0x70, dev->iobase + PCL816_CTRCTL);
- outb(0x30, dev->iobase + PCL816_CTRCTL);
- outb(0, dev->iobase + PCL816_RANGE);
-}
+ if (!devpriv->ai_cmd_running)
+ return 0;
-/*
-==============================================================================
- Start/stop pacer onboard pacer
-*/
-static void
-start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
- unsigned int divisor2)
-{
- outb(0x32, dev->iobase + PCL816_CTRCTL);
- outb(0xff, dev->iobase + PCL816_CTR0);
- outb(0x00, dev->iobase + PCL816_CTR0);
- udelay(1);
+ outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG);
+ pcl816_ai_clear_eoc(dev);
- /* set counter 2 as mode 3 */
- outb(0xb4, dev->iobase + PCL816_CTRCTL);
- /* set counter 1 as mode 3 */
- outb(0x74, dev->iobase + PCL816_CTRCTL);
- udelay(1);
+ /* Stop pacer */
+ i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0,
+ 2, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0,
+ 1, I8254_MODE0 | I8254_BINARY);
- if (mode == 1) {
- DPRINTK("mode %d, divisor1 %d, divisor2 %d\n", mode, divisor1,
- divisor2);
- outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2);
- outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2);
- outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1);
- outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1);
- }
+ devpriv->ai_cmd_running = 0;
+ devpriv->ai_cmd_canceled = 1;
- /* clear pending interrupts (just in case) */
-/* outb(0, dev->iobase + PCL816_CLRINT); */
+ return 0;
}
-/*
-==============================================================================
- Check if channel list from user is built correctly
- If it's ok, then return non-zero length of repeated segment of channel list
-*/
static int
check_channel_list(struct comedi_device *dev,
struct comedi_subdevice *s, unsigned int *chanlist,
@@ -823,11 +560,6 @@ check_channel_list(struct comedi_device *dev,
/* first channel is every time ok */
chansegment[0] = chanlist[0];
for (i = 1, seglen = 1; i < chanlen; i++, seglen++) {
- /* build part of chanlist */
- DEBUG(printk(KERN_INFO "%d. %d %d\n", i,
- CR_CHAN(chanlist[i]),
- CR_RANGE(chanlist[i]));)
-
/* we detect loop, this must by finish */
if (chanlist[0] == chanlist[i])
break;
@@ -835,12 +567,10 @@ check_channel_list(struct comedi_device *dev,
(CR_CHAN(chansegment[i - 1]) + 1) % chanlen;
if (nowmustbechan != CR_CHAN(chanlist[i])) {
/* channel list isn't continuous :-( */
- printk(KERN_WARNING
- "comedi%d: pcl816: channel list must "
- "be continuous! chanlist[%i]=%d but "
- "must be %d or %d!\n", dev->minor,
- i, CR_CHAN(chanlist[i]), nowmustbechan,
- CR_CHAN(chanlist[0]));
+ dev_dbg(dev->class_dev,
+ "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
+ i, CR_CHAN(chanlist[i]), nowmustbechan,
+ CR_CHAN(chanlist[0]));
return 0;
}
/* well, this is next correct channel in list */
@@ -849,22 +579,15 @@ check_channel_list(struct comedi_device *dev,
/* check whole chanlist */
for (i = 0, segpos = 0; i < chanlen; i++) {
- DEBUG(printk("%d %d=%d %d\n",
- CR_CHAN(chansegment[i % seglen]),
- CR_RANGE(chansegment[i % seglen]),
- CR_CHAN(chanlist[i]),
- CR_RANGE(chanlist[i]));)
if (chanlist[i] != chansegment[i % seglen]) {
- printk(KERN_WARNING
- "comedi%d: pcl816: bad channel or range"
- " number! chanlist[%i]=%d,%d,%d and not"
- " %d,%d,%d!\n", dev->minor, i,
- CR_CHAN(chansegment[i]),
- CR_RANGE(chansegment[i]),
- CR_AREF(chansegment[i]),
- CR_CHAN(chanlist[i % seglen]),
- CR_RANGE(chanlist[i % seglen]),
- CR_AREF(chansegment[i % seglen]));
+ dev_dbg(dev->class_dev,
+ "bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
+ i, CR_CHAN(chansegment[i]),
+ CR_RANGE(chansegment[i]),
+ CR_AREF(chansegment[i]),
+ CR_CHAN(chanlist[i % seglen]),
+ CR_RANGE(chanlist[i % seglen]),
+ CR_AREF(chansegment[i % seglen]));
return 0; /* chan/gain list is strange */
}
}
@@ -875,207 +598,182 @@ check_channel_list(struct comedi_device *dev,
return seglen; /* we can serve this with MUX logic */
}
-/*
-==============================================================================
- Program scan/gain logic with channel list.
-*/
-static void
-setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int *chanlist,
- unsigned int seglen)
+static int pcl816_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct pcl816_private *devpriv = dev->private;
- unsigned int i;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ int ret = 0;
+ int i;
+
+ outb(PCL816_CTRL_SOFT_TRIG, dev->iobase + PCL816_CTRL_REG);
+
+ pcl816_ai_set_chan_range(dev, chan, range);
+ pcl816_ai_set_chan_scan(dev, chan, chan);
+
+ for (i = 0; i < insn->n; i++) {
+ pcl816_ai_clear_eoc(dev);
+ pcl816_ai_soft_trig(dev);
+
+ ret = comedi_timeout(dev, s, insn, pcl816_ai_eoc, 0);
+ if (ret)
+ break;
+
+ data[i] = pcl816_ai_get_sample(dev, s);
+ }
+ outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG);
+ pcl816_ai_clear_eoc(dev);
+
+ return ret ? ret : insn->n;
+}
- devpriv->ai_act_chanlist_len = seglen;
- devpriv->ai_act_chanlist_pos = 0;
+static int pcl816_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ data[1] = inb(dev->iobase + PCL816_DO_DI_LSB_REG) |
+ (inb(dev->iobase + PCL816_DO_DI_MSB_REG) << 8);
+
+ return insn->n;
+}
- for (i = 0; i < seglen; i++) { /* store range list to card */
- devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]);
- outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX);
- /* select gain */
- outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE);
+static int pcl816_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (comedi_dio_update_state(s, data)) {
+ outb(s->state & 0xff, dev->iobase + PCL816_DO_DI_LSB_REG);
+ outb((s->state >> 8), dev->iobase + PCL816_DO_DI_MSB_REG);
}
- udelay(1);
- /* select channel interval to scan */
- outb(devpriv->ai_act_chanlist[0] |
- (devpriv->ai_act_chanlist[seglen - 1] << 4),
- dev->iobase + PCL816_MUX);
+ data[1] = s->state;
+
+ return insn->n;
+}
+
+static void pcl816_reset(struct comedi_device *dev)
+{
+ unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE;
+
+ outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG);
+ pcl816_ai_set_chan_range(dev, 0, 0);
+ pcl816_ai_clear_eoc(dev);
+
+ /* Stop pacer */
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY);
+
+ /* set all digital outputs low */
+ outb(0, dev->iobase + PCL816_DO_DI_LSB_REG);
+ outb(0, dev->iobase + PCL816_DO_DI_MSB_REG);
}
static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl816_board *board = comedi_board(dev);
struct pcl816_private *devpriv;
- int ret;
- unsigned int irq, dma;
- unsigned long pages;
- /* int i; */
struct comedi_subdevice *s;
-
- ret = comedi_request_region(dev, it->options[0], board->io_range);
- if (ret)
- return ret;
-
- if (pcl816_check(dev->iobase)) {
- printk(KERN_ERR ", I cann't detect board. FAIL!\n");
- return -EIO;
- }
+ int ret;
+ int i;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- /* grab our IRQ */
- irq = 0;
- if (board->IRQbits != 0) { /* board support IRQ */
- irq = it->options[1];
- if (irq) { /* we want to use IRQ */
- if (((1 << irq) & board->IRQbits) == 0) {
- printk
- (", IRQ %u is out of allowed range, "
- "DISABLING IT", irq);
- irq = 0; /* Bad IRQ */
- } else {
- if (request_irq(irq, interrupt_pcl816, 0,
- dev->board_name, dev)) {
- printk
- (", unable to allocate IRQ %u, "
- "DISABLING IT", irq);
- irq = 0; /* Can't use IRQ */
- } else {
- printk(KERN_INFO ", irq=%u", irq);
- }
- }
- }
+ ret = comedi_request_region(dev, it->options[0], 0x10);
+ if (ret)
+ return ret;
+
+ /* we can use IRQ 2-7 for async command support */
+ if (it->options[1] >= 2 && it->options[1] <= 7) {
+ ret = request_irq(it->options[1], pcl816_interrupt, 0,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = it->options[1];
}
- dev->irq = irq;
- if (irq) /* 1=we have allocated irq */
- devpriv->irq_free = 1;
- else
- devpriv->irq_free = 0;
-
- devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
- devpriv->int816_mode = 0; /* mode of irq */
-
- /* grab our DMA */
- dma = 0;
- devpriv->dma = dma;
- if (!devpriv->irq_free)
- goto no_dma; /* if we haven't IRQ, we can't use DMA */
-
- if (board->DMAbits != 0) { /* board support DMA */
- dma = it->options[2];
- if (dma < 1)
- goto no_dma; /* DMA disabled */
-
- if (((1 << dma) & board->DMAbits) == 0) {
- printk(", DMA is out of allowed range, FAIL!\n");
- return -EINVAL; /* Bad DMA */
- }
- ret = request_dma(dma, dev->board_name);
+ /* we need an IRQ to do DMA on channel 3 or 1 */
+ if (dev->irq && (it->options[2] == 3 || it->options[2] == 1)) {
+ ret = request_dma(it->options[2], dev->board_name);
if (ret) {
- printk(KERN_ERR
- ", unable to allocate DMA %u, FAIL!\n", dma);
- return -EBUSY; /* DMA isn't free */
- }
-
- devpriv->dma = dma;
- printk(KERN_INFO ", dma=%u", dma);
- pages = 2; /* we need 16KB */
- devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
-
- if (!devpriv->dmabuf[0]) {
- printk(", unable to allocate DMA buffer, FAIL!\n");
- /*
- * maybe experiment with try_to_free_pages()
- * will help ....
- */
- return -EBUSY; /* no buffer :-( */
- }
- devpriv->dmapages[0] = pages;
- devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
- devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
- /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
-
- devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[1]) {
- printk(KERN_ERR
- ", unable to allocate DMA buffer, "
- "FAIL!\n");
+ dev_err(dev->class_dev,
+ "unable to request DMA channel %d\n",
+ it->options[2]);
return -EBUSY;
}
- devpriv->dmapages[1] = pages;
- devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
- devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
- }
+ devpriv->dma = it->options[2];
-no_dma:
+ devpriv->dmapages = 2; /* we need 16KB */
+ devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
-/* if (board->n_aochan > 0)
- subdevs[1] = COMEDI_SUBD_AO;
- if (board->n_dichan > 0)
- subdevs[2] = COMEDI_SUBD_DI;
- if (board->n_dochan > 0)
- subdevs[3] = COMEDI_SUBD_DO;
-*/
+ for (i = 0; i < 2; i++) {
+ unsigned long dmabuf;
+
+ dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
+ if (!dmabuf)
+ return -ENOMEM;
+
+ devpriv->dmabuf[i] = dmabuf;
+ devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
+ }
+ }
- ret = comedi_alloc_subdevices(dev, 1);
+ ret = comedi_alloc_subdevices(dev, 4);
if (ret)
return ret;
s = &dev->subdevices[0];
- if (board->n_aichan > 0) {
- s->type = COMEDI_SUBD_AI;
- devpriv->sub_ai = s;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_CMD_READ | SDF_DIFF;
+ s->n_chan = 16;
+ s->maxdata = board->ai_maxdata;
+ s->range_table = &range_pcl816;
+ s->insn_read = pcl816_ai_insn_read;
+ if (devpriv->dma) {
dev->read_subdev = s;
- s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
- s->n_chan = board->n_aichan;
- s->subdev_flags |= SDF_DIFF;
- /* printk (", %dchans DIFF DAC - %d", s->n_chan, i); */
- s->maxdata = board->ai_maxdata;
- s->len_chanlist = board->ai_chanlist;
- s->range_table = board->ai_range_type;
- s->cancel = pcl816_ai_cancel;
- s->do_cmdtest = pcl816_ai_cmdtest;
- s->do_cmd = pcl816_ai_cmd;
- s->poll = pcl816_ai_poll;
- s->insn_read = pcl816_ai_insn_read;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = board->ai_chanlist;
+ s->do_cmdtest = pcl816_ai_cmdtest;
+ s->do_cmd = pcl816_ai_cmd;
+ s->poll = pcl816_ai_poll;
+ s->cancel = pcl816_ai_cancel;
}
+ /* Analog OUtput subdevice */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_UNUSED;
#if 0
-case COMEDI_SUBD_AO:
+ subdevs[1] = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
- s->n_chan = board->n_aochan;
+ s->n_chan = 1;
s->maxdata = board->ao_maxdata;
- s->len_chanlist = board->ao_chanlist;
- s->range_table = board->ao_range_type;
- break;
-
-case COMEDI_SUBD_DI:
- s->subdev_flags = SDF_READABLE;
- s->n_chan = board->n_dichan;
- s->maxdata = 1;
- s->len_chanlist = board->n_dichan;
- s->range_table = &range_digital;
- break;
-
-case COMEDI_SUBD_DO:
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = board->n_dochan;
- s->maxdata = 1;
- s->len_chanlist = board->n_dochan;
- s->range_table = &range_digital;
- break;
+ s->range_table = &range_pcl816;
#endif
- pcl816_reset(dev);
+ /* 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->range_table = &range_digital;
+ s->insn_bits = pcl816_di_insn_bits;
+
+ /* Digital Output subdevice */
+ s = &dev->subdevices[3];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcl816_do_insn_bits;
- printk("\n");
+ pcl816_reset(dev);
return 0;
}
@@ -1085,39 +783,18 @@ static void pcl816_detach(struct comedi_device *dev)
struct pcl816_private *devpriv = dev->private;
if (dev->private) {
- pcl816_ai_cancel(dev, devpriv->sub_ai);
+ pcl816_ai_cancel(dev, dev->read_subdev);
pcl816_reset(dev);
if (devpriv->dma)
free_dma(devpriv->dma);
if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
+ free_pages(devpriv->dmabuf[0], devpriv->dmapages);
if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
+ free_pages(devpriv->dmabuf[1], devpriv->dmapages);
}
comedi_legacy_detach(dev);
}
-static const struct pcl816_board boardtypes[] = {
- {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
- &range_pcl816, PCLx1x_RANGE,
- 0x00fc, /* IRQ mask */
- 0x0a, /* DMA mask */
- 0xffff, /* 16-bit card */
- 0xffff, /* D/A maxdata */
- 1024,
- 1, /* ao chan list */
- I8254_OSC_BASE_10MHZ},
- {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
- &range_pcl816, PCLx1x_RANGE,
- 0x00fc,
- 0x0a,
- 0x3fff, /* 14 bit card */
- 0x3fff,
- 1024,
- 1,
- I8254_OSC_BASE_10MHZ},
-};
-
static struct comedi_driver pcl816_driver = {
.driver_name = "pcl816",
.module = THIS_MODULE,
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index 9e4d7e86050..7d00ae639d3 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -110,8 +110,6 @@ A word or two about DMA. Driver support DMA operations at two ways:
#include "comedi_fc.h"
#include "8253.h"
-/* #define PCL818_MODE13_AO 1 */
-
/* boards constants */
#define boardPCL818L 0
@@ -121,46 +119,38 @@ A word or two about DMA. Driver support DMA operations at two ways:
#define boardPCL818 4
#define boardPCL718 5
-/* IO space len */
-#define PCLx1x_RANGE 16
-/* IO space len if we use FIFO */
-#define PCLx1xFIFO_RANGE 32
-
-/* W: clear INT request */
-#define PCL818_CLRINT 8
-/* R: return status byte */
-#define PCL818_STATUS 8
-/* R: A/D high byte W: A/D range control */
-#define PCL818_RANGE 1
-/* R: next mux scan channel W: mux scan channel & range control pointer */
-#define PCL818_MUX 2
-/* R/W: operation control register */
-#define PCL818_CONTROL 9
-/* W: counter enable */
-#define PCL818_CNTENABLE 10
-
-/* R: low byte of A/D W: soft A/D trigger */
-#define PCL818_AD_LO 0
-/* R: high byte of A/D W: A/D range control */
-#define PCL818_AD_HI 1
-/* W: D/A low&high byte */
-#define PCL818_DA_LO 4
-#define PCL818_DA_HI 5
-/* R: low&high byte of DI */
-#define PCL818_DI_LO 3
-#define PCL818_DI_HI 11
-/* W: low&high byte of DO */
-#define PCL818_DO_LO 3
-#define PCL818_DO_HI 11
-/* W: PCL718 second D/A */
-#define PCL718_DA2_LO 6
-#define PCL718_DA2_HI 7
-/* counters */
-#define PCL818_CTR0 12
-#define PCL818_CTR1 13
-#define PCL818_CTR2 14
-/* W: counter control */
-#define PCL818_CTRCTL 15
+/*
+ * Register I/O map
+ */
+#define PCL818_AI_LSB_REG 0x00
+#define PCL818_AI_MSB_REG 0x01
+#define PCL818_RANGE_REG 0x01
+#define PCL818_MUX_REG 0x02
+#define PCL818_MUX_SCAN(_first, _last) (((_last) << 4) | (_first))
+#define PCL818_DO_DI_LSB_REG 0x03
+#define PCL818_AO_LSB_REG(x) (0x04 + ((x) * 2))
+#define PCL818_AO_MSB_REG(x) (0x05 + ((x) * 2))
+#define PCL818_STATUS_REG 0x08
+#define PCL818_STATUS_NEXT_CHAN_MASK (0xf << 0)
+#define PCL818_STATUS_INT (1 << 4)
+#define PCL818_STATUS_MUX (1 << 5)
+#define PCL818_STATUS_UNI (1 << 6)
+#define PCL818_STATUS_EOC (1 << 7)
+#define PCL818_CTRL_REG 0x09
+#define PCL818_CTRL_DISABLE_TRIG (0 << 0)
+#define PCL818_CTRL_SOFT_TRIG (1 << 0)
+#define PCL818_CTRL_EXT_TRIG (2 << 0)
+#define PCL818_CTRL_PACER_TRIG (3 << 0)
+#define PCL818_CTRL_DMAE (1 << 2)
+#define PCL818_CTRL_IRQ(x) ((x) << 4)
+#define PCL818_CTRL_INTE (1 << 7)
+#define PCL818_CNTENABLE_REG 0x0a
+#define PCL818_CNTENABLE_PACER_ENA (0 << 0)
+#define PCL818_CNTENABLE_PACER_TRIG0 (1 << 0)
+#define PCL818_CNTENABLE_CNT0_EXT_CLK (0 << 1)
+#define PCL818_CNTENABLE_CNT0_INT_CLK (1 << 1)
+#define PCL818_DO_DI_MSB_REG 0x0b
+#define PCL818_TIMER_BASE 0x0c
/* W: fifo enable/disable */
#define PCL818_FI_ENABLE 6
@@ -172,715 +162,517 @@ A word or two about DMA. Driver support DMA operations at two ways:
#define PCL818_FI_STATUS 25
/* R: one record from FIFO */
#define PCL818_FI_DATALO 23
-#define PCL818_FI_DATAHI 23
-
-/* type of interrupt handler */
-#define INT_TYPE_AI1_INT 1
-#define INT_TYPE_AI1_DMA 2
-#define INT_TYPE_AI1_FIFO 3
-#define INT_TYPE_AI3_INT 4
-#define INT_TYPE_AI3_DMA 5
-#define INT_TYPE_AI3_FIFO 6
-#ifdef PCL818_MODE13_AO
-#define INT_TYPE_AO1_INT 7
-#define INT_TYPE_AO3_INT 8
-#endif
+#define PCL818_FI_DATAHI 24
#define MAGIC_DMA_WORD 0x5a5a
-static const struct comedi_lrange range_pcl818h_ai = { 9, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2.5),
- UNI_RANGE(1.25),
- BIP_RANGE(10),
- }
+static const struct comedi_lrange range_pcl818h_ai = {
+ 9, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25),
+ BIP_RANGE(10)
+ }
};
-static const struct comedi_lrange range_pcl818hg_ai = { 10, {
- BIP_RANGE(5),
- BIP_RANGE(0.5),
- BIP_RANGE(0.05),
- BIP_RANGE(0.005),
- UNI_RANGE(10),
- UNI_RANGE(1),
- UNI_RANGE(0.1),
- UNI_RANGE(0.01),
- BIP_RANGE(10),
- BIP_RANGE(1),
- BIP_RANGE(0.1),
- BIP_RANGE(0.01),
- }
+static const struct comedi_lrange range_pcl818hg_ai = {
+ 10, {
+ BIP_RANGE(5),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.05),
+ BIP_RANGE(0.005),
+ UNI_RANGE(10),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1),
+ UNI_RANGE(0.01),
+ BIP_RANGE(10),
+ BIP_RANGE(1),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.01)
+ }
};
-static const struct comedi_lrange range_pcl818l_l_ai = { 4, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- BIP_RANGE(0.625),
- }
+static const struct comedi_lrange range_pcl818l_l_ai = {
+ 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625)
+ }
};
-static const struct comedi_lrange range_pcl818l_h_ai = { 4, {
- BIP_RANGE(10),
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1.25),
- }
+static const struct comedi_lrange range_pcl818l_h_ai = {
+ 4, {
+ BIP_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25)
+ }
+};
+
+static const struct comedi_lrange range718_bipolar1 = {
+ 1, {
+ BIP_RANGE(1)
+ }
};
-static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} };
static const struct comedi_lrange range718_bipolar0_5 = {
- 1, {BIP_RANGE(0.5),} };
-static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
-static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
+ 1, {
+ BIP_RANGE(0.5)
+ }
+};
+
+static const struct comedi_lrange range718_unipolar2 = {
+ 1, {
+ UNI_RANGE(2)
+ }
+};
+
+static const struct comedi_lrange range718_unipolar1 = {
+ 1, {
+ BIP_RANGE(1)
+ }
+};
struct pcl818_board {
+ const char *name;
+ unsigned int ns_min;
+ int n_aochan;
+ const struct comedi_lrange *ai_range_type;
+ unsigned int has_dma:1;
+ unsigned int has_fifo:1;
+ unsigned int is_818:1;
+};
- const char *name; /* driver name */
- int n_ranges; /* len of range list */
- int n_aichan_se; /* num of A/D chans in single ended mode */
- int n_aichan_diff; /* num of A/D chans in diferencial mode */
- unsigned int ns_min; /* minimal allowed delay between samples (in ns) */
- int n_aochan; /* num of D/A chans */
- int n_dichan; /* num of DI chans */
- int n_dochan; /* num of DO chans */
- const struct comedi_lrange *ai_range_type; /* default A/D rangelist */
- const struct comedi_lrange *ao_range_type; /* default D/A rangelist */
- unsigned int io_range; /* len of IO space */
- unsigned int IRQbits; /* allowed interrupts */
- unsigned int DMAbits; /* allowed DMA chans */
- int ai_maxdata; /* maxdata for A/D */
- int ao_maxdata; /* maxdata for D/A */
- unsigned char fifo; /* 1=board has FIFO */
- int is_818;
+static const struct pcl818_board boardtypes[] = {
+ {
+ .name = "pcl818l",
+ .ns_min = 25000,
+ .n_aochan = 1,
+ .ai_range_type = &range_pcl818l_l_ai,
+ .has_dma = 1,
+ .is_818 = 1,
+ }, {
+ .name = "pcl818h",
+ .ns_min = 10000,
+ .n_aochan = 1,
+ .ai_range_type = &range_pcl818h_ai,
+ .has_dma = 1,
+ .is_818 = 1,
+ }, {
+ .name = "pcl818hd",
+ .ns_min = 10000,
+ .n_aochan = 1,
+ .ai_range_type = &range_pcl818h_ai,
+ .has_dma = 1,
+ .has_fifo = 1,
+ .is_818 = 1,
+ }, {
+ .name = "pcl818hg",
+ .ns_min = 10000,
+ .n_aochan = 1,
+ .ai_range_type = &range_pcl818hg_ai,
+ .has_dma = 1,
+ .has_fifo = 1,
+ .is_818 = 1,
+ }, {
+ .name = "pcl818",
+ .ns_min = 10000,
+ .n_aochan = 2,
+ .ai_range_type = &range_pcl818h_ai,
+ .has_dma = 1,
+ .is_818 = 1,
+ }, {
+ .name = "pcl718",
+ .ns_min = 16000,
+ .n_aochan = 2,
+ .ai_range_type = &range_unipolar5,
+ .has_dma = 1,
+ }, {
+ .name = "pcm3718",
+ .ns_min = 10000,
+ .ai_range_type = &range_pcl818h_ai,
+ .has_dma = 1,
+ .is_818 = 1,
+ },
};
struct pcl818_private {
-
unsigned int dma; /* used DMA, 0=don't use DMA */
- unsigned int io_range;
+ unsigned int dmapages;
+ unsigned int hwdmasize;
unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
- unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
- unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
int next_dma_buf; /* which DMA buffer will be used next round */
long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
- unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */
unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */
int i8253_osc_base; /* 1/frequency of on board oscilator in ns */
- int irq_free; /* 1=have allocated IRQ */
- int irq_blocked; /* 1=IRQ now uses any subdev */
- int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */
- int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
- struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
int ai_act_scan; /* how many scans we finished */
int ai_act_chan; /* actual position in actual scan */
unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */
unsigned int act_chanlist_len; /* how long is actual MUX list */
unsigned int act_chanlist_pos; /* actual position in MUX list */
- unsigned int ai_scans; /* len of scanlist */
- unsigned int ai_n_chan; /* how many channels is measured */
- unsigned int *ai_chanlist; /* actaul chanlist */
- unsigned int ai_flags; /* flaglist */
unsigned int ai_data_len; /* len of data buffer */
- unsigned int ai_timer1; /* timers */
- unsigned int ai_timer2;
- struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
- unsigned char usefifo; /* 1=use fifo */
unsigned int ao_readback[2];
+ unsigned int divisor1;
+ unsigned int divisor2;
+ unsigned int usefifo:1;
+ unsigned int ai_cmd_running:1;
+ unsigned int ai_cmd_canceled:1;
};
-static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */
- 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
-};
-
-/*
-==============================================================================
-*/
-static void setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan,
- unsigned int seglen);
-static int check_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan);
-
-static int pcl818_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2);
-
-/*
-==============================================================================
- ANALOG INPUT MODE0, 818 cards, slow version
-*/
-static int pcl818_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl818_start_pacer(struct comedi_device *dev, bool load_counters)
{
- int n;
- int timeout;
+ struct pcl818_private *devpriv = dev->private;
+ unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE;
- /* software trigger, DMA and INT off */
- outb(0, dev->iobase + PCL818_CONTROL);
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
+ udelay(1);
- /* select channel */
- outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX);
+ if (load_counters) {
+ i8254_write(timer_base, 0, 2, devpriv->divisor2);
+ i8254_write(timer_base, 0, 1, devpriv->divisor1);
+ }
+}
- /* select gain */
- outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE);
+static void pcl818_ai_setup_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct pcl818_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int flags;
+ unsigned int bytes;
- for (n = 0; n < insn->n; n++) {
+ disable_dma(devpriv->dma); /* disable dma */
+ bytes = devpriv->hwdmasize;
+ if (cmd->stop_src == TRIG_COUNT) {
+ bytes = cmd->stop_arg * cfc_bytes_per_scan(s);
+ devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize;
+ devpriv->last_dma_run = bytes % devpriv->hwdmasize;
+ devpriv->dma_runs_to_end--;
+ if (devpriv->dma_runs_to_end >= 0)
+ bytes = devpriv->hwdmasize;
+ }
- /* clear INT (conversion end) flag */
- outb(0, dev->iobase + PCL818_CLRINT);
+ devpriv->next_dma_buf = 0;
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ flags = claim_dma_lock();
+ clear_dma_ff(devpriv->dma);
+ set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
+ set_dma_count(devpriv->dma, bytes);
+ release_dma_lock(flags);
+ enable_dma(devpriv->dma);
+}
- /* start conversion */
- outb(0, dev->iobase + PCL818_AD_LO);
+static void pcl818_ai_setup_next_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct pcl818_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned long flags;
- timeout = 100;
- while (timeout--) {
- if (inb(dev->iobase + PCL818_STATUS) & 0x10)
- goto conv_finish;
- udelay(1);
- }
- comedi_error(dev, "A/D insn timeout");
- /* clear INT (conversion end) flag */
- outb(0, dev->iobase + PCL818_CLRINT);
- return -EIO;
-
-conv_finish:
- data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) |
- (inb(dev->iobase + PCL818_AD_LO) >> 4));
+ disable_dma(devpriv->dma);
+ devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
+ if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) {
+ /* switch dma bufs */
+ set_dma_mode(devpriv->dma, DMA_MODE_READ);
+ flags = claim_dma_lock();
+ set_dma_addr(devpriv->dma,
+ devpriv->hwdmaptr[devpriv->next_dma_buf]);
+ if (devpriv->dma_runs_to_end || cmd->stop_src == TRIG_NONE)
+ set_dma_count(devpriv->dma, devpriv->hwdmasize);
+ else
+ set_dma_count(devpriv->dma, devpriv->last_dma_run);
+ release_dma_lock(flags);
+ enable_dma(devpriv->dma);
}
- return n;
+ devpriv->dma_runs_to_end--;
}
-/*
-==============================================================================
- ANALOG OUTPUT MODE0, 818 cards
- only one sample per call is supported
-*/
-static int pcl818_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl818_ai_set_chan_range(struct comedi_device *dev,
+ unsigned int chan,
+ unsigned int range)
{
- struct pcl818_private *devpriv = dev->private;
- int n;
- int chan = CR_CHAN(insn->chanspec);
-
- for (n = 0; n < insn->n; n++)
- data[n] = devpriv->ao_readback[chan];
+ outb(chan, dev->iobase + PCL818_MUX_REG);
+ outb(range, dev->iobase + PCL818_RANGE_REG);
+}
- return n;
+static void pcl818_ai_set_chan_scan(struct comedi_device *dev,
+ unsigned int first_chan,
+ unsigned int last_chan)
+{
+ outb(PCL818_MUX_SCAN(first_chan, last_chan),
+ dev->iobase + PCL818_MUX_REG);
}
-static int pcl818_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl818_ai_setup_chanlist(struct comedi_device *dev,
+ unsigned int *chanlist,
+ unsigned int seglen)
{
struct pcl818_private *devpriv = dev->private;
- int n;
- int chan = CR_CHAN(insn->chanspec);
-
- for (n = 0; n < insn->n; n++) {
- devpriv->ao_readback[chan] = data[n];
- outb((data[n] & 0x000f) << 4, dev->iobase +
- (chan ? PCL718_DA2_LO : PCL818_DA_LO));
- outb((data[n] & 0x0ff0) >> 4, dev->iobase +
- (chan ? PCL718_DA2_HI : PCL818_DA_HI));
+ unsigned int first_chan = CR_CHAN(chanlist[0]);
+ unsigned int last_chan;
+ unsigned int range;
+ int i;
+
+ devpriv->act_chanlist_len = seglen;
+ devpriv->act_chanlist_pos = 0;
+
+ /* store range list to card */
+ for (i = 0; i < seglen; i++) {
+ last_chan = CR_CHAN(chanlist[i]);
+ range = CR_RANGE(chanlist[i]);
+
+ devpriv->act_chanlist[i] = last_chan;
+
+ pcl818_ai_set_chan_range(dev, last_chan, range);
}
- return n;
+ udelay(1);
+
+ pcl818_ai_set_chan_scan(dev, first_chan, last_chan);
}
-/*
-==============================================================================
- DIGITAL INPUT MODE0, 818 cards
+static void pcl818_ai_clear_eoc(struct comedi_device *dev)
+{
+ /* writing any value clears the interrupt request */
+ outb(0, dev->iobase + PCL818_STATUS_REG);
+}
- only one sample per call is supported
-*/
-static int pcl818_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static void pcl818_ai_soft_trig(struct comedi_device *dev)
{
- data[1] = inb(dev->iobase + PCL818_DI_LO) |
- (inb(dev->iobase + PCL818_DI_HI) << 8);
+ /* writing any value triggers a software conversion */
+ outb(0, dev->iobase + PCL818_AI_LSB_REG);
+}
- return insn->n;
+static unsigned int pcl818_ai_get_fifo_sample(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int *chan)
+{
+ unsigned int val;
+
+ val = inb(dev->iobase + PCL818_FI_DATALO);
+ val |= (inb(dev->iobase + PCL818_FI_DATAHI) << 8);
+
+ if (chan)
+ *chan = val & 0xf;
+
+ return (val >> 4) & s->maxdata;
}
-static int pcl818_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static unsigned int pcl818_ai_get_sample(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int *chan)
{
- if (comedi_dio_update_state(s, data)) {
- outb(s->state & 0xff, dev->iobase + PCL818_DO_LO);
- outb((s->state >> 8), dev->iobase + PCL818_DO_HI);
- }
+ unsigned int val;
- data[1] = s->state;
+ val = inb(dev->iobase + PCL818_AI_MSB_REG) << 8;
+ val |= inb(dev->iobase + PCL818_AI_LSB_REG);
- return insn->n;
+ if (chan)
+ *chan = val & 0xf;
+
+ return (val >> 4) & s->maxdata;
}
-/*
-==============================================================================
- analog input interrupt mode 1 & 3, 818 cards
- one sample per interrupt version
-*/
-static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d)
+static int pcl818_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- struct comedi_device *dev = d;
- struct pcl818_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
- unsigned char low;
- int timeout = 50; /* wait max 50us */
-
- while (timeout--) {
- if (inb(dev->iobase + PCL818_STATUS) & 0x10)
- goto conv_finish;
- udelay(1);
- }
- outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */
- comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ unsigned int status;
+
+ status = inb(dev->iobase + PCL818_STATUS_REG);
+ if (status & PCL818_STATUS_INT)
+ return 0;
+ return -EBUSY;
+}
-conv_finish:
- low = inb(dev->iobase + PCL818_AD_LO);
- comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */
- outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
-
- if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
- printk
- ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
- (low & 0xf),
- devpriv->act_chanlist[devpriv->act_chanlist_pos]);
- pcl818_ai_cancel(dev, s);
+static bool pcl818_ai_dropout(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int chan)
+{
+ struct pcl818_private *devpriv = dev->private;
+ unsigned int expected_chan;
+
+ expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos];
+ if (chan != expected_chan) {
+ dev_dbg(dev->class_dev,
+ "A/D mode1/3 %s - channel dropout %d!=%d !\n",
+ (devpriv->dma) ? "DMA" :
+ (devpriv->usefifo) ? "FIFO" : "IRQ",
+ chan, expected_chan);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ return true;
}
+ return false;
+}
+
+static bool pcl818_ai_next_chan(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct pcl818_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+
+ s->async->events |= COMEDI_CB_BLOCK;
+
devpriv->act_chanlist_pos++;
if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
devpriv->act_chanlist_pos = 0;
s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
- /* printk("E"); */
+ if (s->async->cur_chan >= cmd->chanlist_len) {
s->async->cur_chan = 0;
devpriv->ai_act_scan--;
+ s->async->events |= COMEDI_CB_EOS;
}
- if (!devpriv->neverending_ai) {
- if (devpriv->ai_act_scan == 0) { /* all data sampled */
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- }
+ if (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan == 0) {
+ /* all data sampled */
+ s->async->events |= COMEDI_CB_EOA;
+ return false;
}
- comedi_event(dev, s);
- return IRQ_HANDLED;
+
+ return true;
}
-/*
-==============================================================================
- analog input dma mode 1 & 3, 818 cards
-*/
-static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
+static void pcl818_handle_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ unsigned int chan;
+ unsigned int val;
+
+ if (pcl818_ai_eoc(dev, s, NULL, 0)) {
+ comedi_error(dev, "A/D mode1/3 IRQ without DRDY!");
+ s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ return;
+ }
+
+ val = pcl818_ai_get_sample(dev, s, &chan);
+
+ if (pcl818_ai_dropout(dev, s, chan))
+ return;
+
+ comedi_buf_put(s, val);
+
+ pcl818_ai_next_chan(dev, s);
+}
+
+static void pcl818_handle_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- struct comedi_device *dev = d;
struct pcl818_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
- int i, len, bufptr;
- unsigned long flags;
unsigned short *ptr;
+ unsigned int chan;
+ unsigned int val;
+ int i, len, bufptr;
- disable_dma(devpriv->dma);
- devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
- if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- flags = claim_dma_lock();
- set_dma_addr(devpriv->dma,
- devpriv->hwdmaptr[devpriv->next_dma_buf]);
- if (devpriv->dma_runs_to_end || devpriv->neverending_ai) {
- set_dma_count(devpriv->dma,
- devpriv->hwdmasize[devpriv->
- next_dma_buf]);
- } else {
- set_dma_count(devpriv->dma, devpriv->last_dma_run);
- }
- release_dma_lock(flags);
- enable_dma(devpriv->dma);
- }
- printk("comedi: A/D mode1/3 IRQ \n");
+ pcl818_ai_setup_next_dma(dev, s);
- devpriv->dma_runs_to_end--;
- outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
- len = devpriv->hwdmasize[0] >> 1;
+ len = devpriv->hwdmasize >> 1;
bufptr = 0;
for (i = 0; i < len; i++) {
- if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
- printk
- ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n",
- (ptr[bufptr] & 0xf),
- devpriv->act_chanlist[devpriv->act_chanlist_pos],
- devpriv->act_chanlist_pos);
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
- }
-
- comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */
+ val = ptr[bufptr++];
+ chan = val & 0xf;
+ val = (val >> 4) & s->maxdata;
- devpriv->act_chanlist_pos++;
- if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
- devpriv->act_chanlist_pos = 0;
+ if (pcl818_ai_dropout(dev, s, chan))
+ break;
- s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
- s->async->cur_chan = 0;
- devpriv->ai_act_scan--;
- }
+ comedi_buf_put(s, val);
- if (!devpriv->neverending_ai)
- if (devpriv->ai_act_scan == 0) { /* all data sampled */
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
- /* printk("done int ai13 dma\n"); */
- return IRQ_HANDLED;
- }
+ if (!pcl818_ai_next_chan(dev, s))
+ break;
}
-
- if (len > 0)
- comedi_event(dev, s);
- return IRQ_HANDLED;
}
-/*
-==============================================================================
- analog input interrupt mode 1 & 3, 818HD/HG cards
-*/
-static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d)
+static void pcl818_handle_fifo(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- struct comedi_device *dev = d;
- struct pcl818_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
+ unsigned int status;
+ unsigned int chan;
+ unsigned int val;
int i, len;
- unsigned char lo;
- outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */
+ status = inb(dev->iobase + PCL818_FI_STATUS);
- lo = inb(dev->iobase + PCL818_FI_STATUS);
-
- if (lo & 4) {
+ if (status & 4) {
comedi_error(dev, "A/D mode1/3 FIFO overflow!");
- pcl818_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ return;
}
- if (lo & 1) {
+ if (status & 1) {
comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!");
- pcl818_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
+ return;
}
- if (lo & 2)
+ if (status & 2)
len = 512;
else
len = 0;
for (i = 0; i < len; i++) {
- lo = inb(dev->iobase + PCL818_FI_DATALO);
- if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
- printk
- ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n",
- (lo & 0xf),
- devpriv->act_chanlist[devpriv->act_chanlist_pos]);
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
- }
+ val = pcl818_ai_get_fifo_sample(dev, s, &chan);
- comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */
-
- devpriv->act_chanlist_pos++;
- if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
- devpriv->act_chanlist_pos = 0;
+ if (pcl818_ai_dropout(dev, s, chan))
+ break;
- s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
- s->async->cur_chan = 0;
- devpriv->ai_act_scan--;
- }
+ comedi_buf_put(s, val);
- if (!devpriv->neverending_ai)
- if (devpriv->ai_act_scan == 0) { /* all data sampled */
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
- return IRQ_HANDLED;
- }
+ if (!pcl818_ai_next_chan(dev, s))
+ break;
}
-
- if (len > 0)
- comedi_event(dev, s);
- return IRQ_HANDLED;
}
-/*
-==============================================================================
- INT procedure
-*/
-static irqreturn_t interrupt_pcl818(int irq, void *d)
+static irqreturn_t pcl818_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct pcl818_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
- if (!dev->attached) {
- comedi_error(dev, "premature interrupt");
+ if (!dev->attached || !devpriv->ai_cmd_running) {
+ pcl818_ai_clear_eoc(dev);
return IRQ_HANDLED;
}
- /* printk("I\n"); */
-
- if (devpriv->irq_blocked && devpriv->irq_was_now_closed) {
- if ((devpriv->neverending_ai || (!devpriv->neverending_ai &&
- devpriv->ai_act_scan > 0)) &&
- (devpriv->ai_mode == INT_TYPE_AI1_DMA ||
- devpriv->ai_mode == INT_TYPE_AI3_DMA)) {
- /* The cleanup from ai_cancel() has been delayed
- until now because the card doesn't seem to like
- being reprogrammed while a DMA transfer is in
- progress.
- */
- struct comedi_subdevice *s = &dev->subdevices[0];
- devpriv->ai_act_scan = 0;
- devpriv->neverending_ai = 0;
- pcl818_ai_cancel(dev, s);
- }
-
- outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
+ if (devpriv->ai_cmd_canceled) {
+ /*
+ * The cleanup from ai_cancel() has been delayed
+ * until now because the card doesn't seem to like
+ * being reprogrammed while a DMA transfer is in
+ * progress.
+ */
+ devpriv->ai_act_scan = 0;
+ s->cancel(dev, s);
return IRQ_HANDLED;
}
- switch (devpriv->ai_mode) {
- case INT_TYPE_AI1_DMA:
- case INT_TYPE_AI3_DMA:
- return interrupt_pcl818_ai_mode13_dma(irq, d);
- case INT_TYPE_AI1_INT:
- case INT_TYPE_AI3_INT:
- return interrupt_pcl818_ai_mode13_int(irq, d);
- case INT_TYPE_AI1_FIFO:
- case INT_TYPE_AI3_FIFO:
- return interrupt_pcl818_ai_mode13_fifo(irq, d);
-#ifdef PCL818_MODE13_AO
- case INT_TYPE_AO1_INT:
- case INT_TYPE_AO3_INT:
- return interrupt_pcl818_ao_mode13_int(irq, d);
-#endif
- default:
- break;
- }
-
- outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
-
- if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked)
- || (!devpriv->ai_mode)) {
- comedi_error(dev, "bad IRQ!");
- return IRQ_NONE;
- }
-
- comedi_error(dev, "IRQ from unknown source!");
- return IRQ_NONE;
-}
-
-/*
-==============================================================================
- ANALOG INPUT MODE 1 or 3 DMA , 818 cards
-*/
-static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pcl818_private *devpriv = dev->private;
- unsigned int flags;
- unsigned int bytes;
-
- printk("mode13dma_int, mode: %d\n", mode);
- disable_dma(devpriv->dma); /* disable dma */
- bytes = devpriv->hwdmasize[0];
- if (!devpriv->neverending_ai) {
- bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */
- devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */
- devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */
- devpriv->dma_runs_to_end--;
- if (devpriv->dma_runs_to_end >= 0)
- bytes = devpriv->hwdmasize[0];
- }
-
- devpriv->next_dma_buf = 0;
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- flags = claim_dma_lock();
- clear_dma_ff(devpriv->dma);
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
- set_dma_count(devpriv->dma, bytes);
- release_dma_lock(flags);
- enable_dma(devpriv->dma);
-
- if (mode == 1) {
- devpriv->ai_mode = INT_TYPE_AI1_DMA;
- outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */
- } else {
- devpriv->ai_mode = INT_TYPE_AI3_DMA;
- outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */
- };
-}
-
-/*
-==============================================================================
- ANALOG INPUT MODE 1 or 3, 818 cards
-*/
-static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pcl818_private *devpriv = dev->private;
- struct comedi_cmd *cmd = &s->async->cmd;
- int divisor1 = 0, divisor2 = 0;
- unsigned int seglen;
-
- dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode()\n");
- if (!dev->irq) {
- comedi_error(dev, "IRQ not defined!");
- return -EINVAL;
- }
-
- if (devpriv->irq_blocked)
- return -EBUSY;
-
- start_pacer(dev, -1, 0, 0); /* stop pacer */
-
- seglen = check_channel_list(dev, s, devpriv->ai_chanlist,
- devpriv->ai_n_chan);
- if (seglen < 1)
- return -EINVAL;
- setup_channel_list(dev, s, devpriv->ai_chanlist,
- devpriv->ai_n_chan, seglen);
-
- udelay(1);
-
- devpriv->ai_act_scan = devpriv->ai_scans;
- devpriv->ai_act_chan = 0;
- devpriv->irq_blocked = 1;
- devpriv->irq_was_now_closed = 0;
- devpriv->neverending_ai = 0;
- devpriv->act_chanlist_pos = 0;
- devpriv->dma_runs_to_end = 0;
-
- if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1))
- devpriv->neverending_ai = 1; /* well, user want neverending */
-
- if (mode == 1) {
- i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,
- &divisor1, &divisor2,
- &cmd->convert_arg,
- TRIG_ROUND_NEAREST);
- if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */
- divisor1 = 2;
- divisor2 /= 2;
- }
- if (divisor2 == 1) {
- divisor2 = 2;
- divisor1 /= 2;
- }
- }
-
- outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
-
- switch (devpriv->dma) {
- case 1: /* DMA */
- case 3:
- pcl818_ai_mode13dma_int(mode, dev, s);
- break;
- case 0:
- if (!devpriv->usefifo) {
- /* IRQ */
- /* printk("IRQ\n"); */
- if (mode == 1) {
- devpriv->ai_mode = INT_TYPE_AI1_INT;
- /* Pacer+IRQ */
- outb(0x83 | (dev->irq << 4),
- dev->iobase + PCL818_CONTROL);
- } else {
- devpriv->ai_mode = INT_TYPE_AI3_INT;
- /* Ext trig+IRQ */
- outb(0x82 | (dev->irq << 4),
- dev->iobase + PCL818_CONTROL);
- }
- } else {
- /* FIFO */
- /* enable FIFO */
- outb(1, dev->iobase + PCL818_FI_ENABLE);
- if (mode == 1) {
- devpriv->ai_mode = INT_TYPE_AI1_FIFO;
- /* Pacer */
- outb(0x03, dev->iobase + PCL818_CONTROL);
- } else {
- devpriv->ai_mode = INT_TYPE_AI3_FIFO;
- outb(0x02, dev->iobase + PCL818_CONTROL);
- }
- }
- }
-
- start_pacer(dev, mode, divisor1, divisor2);
-
- dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode() end\n");
- return 0;
-}
+ if (devpriv->dma)
+ pcl818_handle_dma(dev, s);
+ else if (devpriv->usefifo)
+ pcl818_handle_fifo(dev, s);
+ else
+ pcl818_handle_eoc(dev, s);
-/*
-==============================================================================
- Start/stop pacer onboard pacer
-*/
-static void start_pacer(struct comedi_device *dev, int mode,
- unsigned int divisor1, unsigned int divisor2)
-{
- outb(0xb4, dev->iobase + PCL818_CTRCTL);
- outb(0x74, dev->iobase + PCL818_CTRCTL);
- udelay(1);
+ pcl818_ai_clear_eoc(dev);
- if (mode == 1) {
- outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2);
- outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2);
- outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1);
- outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1);
- }
+ cfc_handle_events(dev, s);
+ return IRQ_HANDLED;
}
-/*
-==============================================================================
- Check if channel list from user is builded correctly
- If it's ok, then program scan/gain logic
-*/
static int check_channel_list(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int *chanlist, unsigned int n_chan)
@@ -899,10 +691,6 @@ static int check_channel_list(struct comedi_device *dev,
chansegment[0] = chanlist[0];
/* build part of chanlist */
for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
-
- /* printk("%d. %d * %d\n",i,
- * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/
-
/* we detect loop, this must by finish */
if (chanlist[0] == chanlist[i])
@@ -910,10 +698,10 @@ static int check_channel_list(struct comedi_device *dev,
nowmustbechan =
(CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */
- printk
- ("comedi%d: pcl818: channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
- dev->minor, i, CR_CHAN(chanlist[i]),
- nowmustbechan, CR_CHAN(chanlist[0]));
+ dev_dbg(dev->class_dev,
+ "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
+ i, CR_CHAN(chanlist[i]), nowmustbechan,
+ CR_CHAN(chanlist[0]));
return 0;
}
/* well, this is next correct channel in list */
@@ -922,72 +710,38 @@ static int check_channel_list(struct comedi_device *dev,
/* check whole chanlist */
for (i = 0, segpos = 0; i < n_chan; i++) {
- /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i])); */
if (chanlist[i] != chansegment[i % seglen]) {
- printk
- ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
- dev->minor, i, CR_CHAN(chansegment[i]),
- CR_RANGE(chansegment[i]),
- CR_AREF(chansegment[i]),
- CR_CHAN(chanlist[i % seglen]),
- CR_RANGE(chanlist[i % seglen]),
- CR_AREF(chansegment[i % seglen]));
+ dev_dbg(dev->class_dev,
+ "bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
+ i, CR_CHAN(chansegment[i]),
+ CR_RANGE(chansegment[i]),
+ CR_AREF(chansegment[i]),
+ CR_CHAN(chanlist[i % seglen]),
+ CR_RANGE(chanlist[i % seglen]),
+ CR_AREF(chansegment[i % seglen]));
return 0; /* chan/gain list is strange */
}
}
} else {
seglen = 1;
}
- printk("check_channel_list: seglen %d\n", seglen);
return seglen;
}
-static void setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan,
- unsigned int seglen)
-{
- struct pcl818_private *devpriv = dev->private;
- int i;
-
- devpriv->act_chanlist_len = seglen;
- devpriv->act_chanlist_pos = 0;
-
- for (i = 0; i < seglen; i++) { /* store range list to card */
- devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
- outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */
- outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */
- }
-
- udelay(1);
-
- /* select channel interval to scan */
- outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen -
- 1] << 4),
- dev->iobase + PCL818_MUX);
-}
-
-/*
-==============================================================================
- Check if board is switched to SE (1) or DIFF(0) mode
-*/
static int check_single_ended(unsigned int port)
{
- if (inb(port + PCL818_STATUS) & 0x20)
+ if (inb(port + PCL818_STATUS_REG) & PCL818_STATUS_MUX)
return 1;
return 0;
}
-/*
-==============================================================================
-*/
static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
const struct pcl818_board *board = comedi_board(dev);
struct pcl818_private *devpriv = dev->private;
int err = 0;
- int tmp, divisor1 = 0, divisor2 = 0;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -1034,14 +788,12 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
/* step 4: fix up any arguments */
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
+ arg = cmd->convert_arg;
i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,
- &divisor1, &divisor2,
- &cmd->convert_arg, cmd->flags);
- if (cmd->convert_arg < board->ns_min)
- cmd->convert_arg = board->ns_min;
- if (tmp != cmd->convert_arg)
- err++;
+ &devpriv->divisor1,
+ &devpriv->divisor2,
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
}
if (err)
@@ -1058,156 +810,272 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
-/*
-==============================================================================
-*/
-static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
+static int pcl818_ai_cmd(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct pcl818_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
- int retval;
+ unsigned int ctrl = 0;
+ unsigned int seglen;
+
+ if (devpriv->ai_cmd_running)
+ return -EBUSY;
+
+ pcl818_start_pacer(dev, false);
+
+ seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
+ if (seglen < 1)
+ return -EINVAL;
+ pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen);
- dev_dbg(dev->class_dev, "pcl818_ai_cmd()\n");
- devpriv->ai_n_chan = cmd->chanlist_len;
- devpriv->ai_chanlist = cmd->chanlist;
- devpriv->ai_flags = cmd->flags;
devpriv->ai_data_len = s->async->prealloc_bufsz;
- devpriv->ai_timer1 = 0;
- devpriv->ai_timer2 = 0;
+ devpriv->ai_act_scan = cmd->stop_arg;
+ devpriv->ai_act_chan = 0;
+ devpriv->ai_cmd_running = 1;
+ devpriv->ai_cmd_canceled = 0;
+ devpriv->act_chanlist_pos = 0;
+ devpriv->dma_runs_to_end = 0;
- if (cmd->stop_src == TRIG_COUNT)
- devpriv->ai_scans = cmd->stop_arg;
+ if (cmd->convert_src == TRIG_TIMER)
+ ctrl |= PCL818_CTRL_PACER_TRIG;
else
- devpriv->ai_scans = 0;
-
- if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */
- if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */
- devpriv->ai_timer1 = cmd->convert_arg;
- retval = pcl818_ai_cmd_mode(1, dev, s);
- dev_dbg(dev->class_dev, "pcl818_ai_cmd() end\n");
- return retval;
- }
- if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
- return pcl818_ai_cmd_mode(3, dev, s);
- }
+ ctrl |= PCL818_CTRL_EXT_TRIG;
+
+ outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG);
+
+ if (devpriv->dma) {
+ pcl818_ai_setup_dma(dev, s);
+
+ ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq) |
+ PCL818_CTRL_DMAE;
+ } else if (devpriv->usefifo) {
+ /* enable FIFO */
+ outb(1, dev->iobase + PCL818_FI_ENABLE);
+ } else {
+ ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq);
}
+ outb(ctrl, dev->iobase + PCL818_CTRL_REG);
- return -1;
+ if (cmd->convert_src == TRIG_TIMER)
+ pcl818_start_pacer(dev, true);
+
+ return 0;
}
-/*
-==============================================================================
- cancel any mode 1-4 AI
-*/
static int pcl818_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct pcl818_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
- if (devpriv->irq_blocked > 0) {
- dev_dbg(dev->class_dev, "pcl818_ai_cancel()\n");
- devpriv->irq_was_now_closed = 1;
-
- switch (devpriv->ai_mode) {
- case INT_TYPE_AI1_DMA:
- case INT_TYPE_AI3_DMA:
- if (devpriv->neverending_ai ||
- (!devpriv->neverending_ai &&
- devpriv->ai_act_scan > 0)) {
- /* wait for running dma transfer to end, do cleanup in interrupt */
- goto end;
- }
- disable_dma(devpriv->dma);
- case INT_TYPE_AI1_INT:
- case INT_TYPE_AI3_INT:
- case INT_TYPE_AI1_FIFO:
- case INT_TYPE_AI3_FIFO:
-#ifdef PCL818_MODE13_AO
- case INT_TYPE_AO1_INT:
- case INT_TYPE_AO3_INT:
-#endif
- outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */
- udelay(1);
- start_pacer(dev, -1, 0, 0);
- outb(0, dev->iobase + PCL818_AD_LO);
- inb(dev->iobase + PCL818_AD_LO);
- inb(dev->iobase + PCL818_AD_HI);
- outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */
- outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */
- if (devpriv->usefifo) { /* FIFO shutdown */
- outb(0, dev->iobase + PCL818_FI_INTCLR);
- outb(0, dev->iobase + PCL818_FI_FLUSH);
- outb(0, dev->iobase + PCL818_FI_ENABLE);
+ if (!devpriv->ai_cmd_running)
+ return 0;
+
+ if (devpriv->dma) {
+ if (cmd->stop_src == TRIG_NONE ||
+ (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan > 0)) {
+ if (!devpriv->ai_cmd_canceled) {
+ /*
+ * Wait for running dma transfer to end,
+ * do cleanup in interrupt.
+ */
+ devpriv->ai_cmd_canceled = 1;
+ return 0;
}
- devpriv->irq_blocked = 0;
- devpriv->last_int_sub = s;
- devpriv->neverending_ai = 0;
- devpriv->ai_mode = 0;
- devpriv->irq_was_now_closed = 0;
- break;
}
+ disable_dma(devpriv->dma);
}
-end:
- dev_dbg(dev->class_dev, "pcl818_ai_cancel() end\n");
+ outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG);
+ pcl818_start_pacer(dev, false);
+ pcl818_ai_clear_eoc(dev);
+
+ if (devpriv->usefifo) { /* FIFO shutdown */
+ outb(0, dev->iobase + PCL818_FI_INTCLR);
+ outb(0, dev->iobase + PCL818_FI_FLUSH);
+ outb(0, dev->iobase + PCL818_FI_ENABLE);
+ }
+ devpriv->ai_cmd_running = 0;
+ devpriv->ai_cmd_canceled = 0;
+
return 0;
}
-/*
-==============================================================================
- chech for PCL818
-*/
-static int pcl818_check(unsigned long iobase)
+static int pcl818_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- outb(0x00, iobase + PCL818_MUX);
- udelay(1);
- if (inb(iobase + PCL818_MUX) != 0x00)
- return 1; /* there isn't card */
- outb(0x55, iobase + PCL818_MUX);
- udelay(1);
- if (inb(iobase + PCL818_MUX) != 0x55)
- return 1; /* there isn't card */
- outb(0x00, iobase + PCL818_MUX);
- udelay(1);
- outb(0x18, iobase + PCL818_CONTROL);
- udelay(1);
- if (inb(iobase + PCL818_CONTROL) != 0x18)
- return 1; /* there isn't card */
- return 0; /* ok, card exist */
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ int ret = 0;
+ int i;
+
+ outb(PCL818_CTRL_SOFT_TRIG, dev->iobase + PCL818_CTRL_REG);
+
+ pcl818_ai_set_chan_range(dev, chan, range);
+ pcl818_ai_set_chan_scan(dev, chan, chan);
+
+ for (i = 0; i < insn->n; i++) {
+ pcl818_ai_clear_eoc(dev);
+ pcl818_ai_soft_trig(dev);
+
+ ret = comedi_timeout(dev, s, insn, pcl818_ai_eoc, 0);
+ if (ret)
+ break;
+
+ data[i] = pcl818_ai_get_sample(dev, s, NULL);
+ }
+ pcl818_ai_clear_eoc(dev);
+
+ return ret ? ret : insn->n;
+}
+
+static int pcl818_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct pcl818_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++) {
+ devpriv->ao_readback[chan] = data[i];
+ outb((data[i] & 0x000f) << 4,
+ dev->iobase + PCL818_AO_LSB_REG(chan));
+ outb((data[i] & 0x0ff0) >> 4,
+ dev->iobase + PCL818_AO_MSB_REG(chan));
+ }
+
+ return insn->n;
+}
+
+static int pcl818_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct pcl818_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
+
+ return insn->n;
+}
+
+static int pcl818_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ data[1] = inb(dev->iobase + PCL818_DO_DI_LSB_REG) |
+ (inb(dev->iobase + PCL818_DO_DI_MSB_REG) << 8);
+
+ return insn->n;
+}
+
+static int pcl818_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (comedi_dio_update_state(s, data)) {
+ outb(s->state & 0xff, dev->iobase + PCL818_DO_DI_LSB_REG);
+ outb((s->state >> 8), dev->iobase + PCL818_DO_DI_MSB_REG);
+ }
+
+ data[1] = s->state;
+
+ return insn->n;
}
-/*
-==============================================================================
- reset whole PCL-818 cards
-*/
static void pcl818_reset(struct comedi_device *dev)
{
const struct pcl818_board *board = comedi_board(dev);
- struct pcl818_private *devpriv = dev->private;
+ unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE;
+ unsigned int chan;
- if (devpriv->usefifo) { /* FIFO shutdown */
+ /* flush and disable the FIFO */
+ if (board->has_fifo) {
outb(0, dev->iobase + PCL818_FI_INTCLR);
outb(0, dev->iobase + PCL818_FI_FLUSH);
outb(0, dev->iobase + PCL818_FI_ENABLE);
}
- outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */
- outb(0, dev->iobase + PCL818_DA_HI);
- udelay(1);
- outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */
- outb(0, dev->iobase + PCL818_DO_LO);
- udelay(1);
- outb(0, dev->iobase + PCL818_CONTROL);
- outb(0, dev->iobase + PCL818_CNTENABLE);
- outb(0, dev->iobase + PCL818_MUX);
- outb(0, dev->iobase + PCL818_CLRINT);
- outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */
- outb(0x70, dev->iobase + PCL818_CTRCTL);
- outb(0x30, dev->iobase + PCL818_CTRCTL);
+
+ /* disable analog input trigger */
+ outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG);
+ pcl818_ai_clear_eoc(dev);
+
+ pcl818_ai_set_chan_range(dev, 0, 0);
+
+ /* stop pacer */
+ outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG);
+ i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY);
+ i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY);
+
+ /* set analog output channels to 0V */
+ for (chan = 0; chan < board->n_aochan; chan++) {
+ outb(0, dev->iobase + PCL818_AO_LSB_REG(chan));
+ outb(0, dev->iobase + PCL818_AO_MSB_REG(chan));
+ }
+
+ /* set all digital outputs low */
+ outb(0, dev->iobase + PCL818_DO_DI_MSB_REG);
+ outb(0, dev->iobase + PCL818_DO_DI_LSB_REG);
+}
+
+static void pcl818_set_ai_range_table(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_devconfig *it)
+{
+ const struct pcl818_board *board = comedi_board(dev);
+
+ /* default to the range table from the boardinfo */
+ s->range_table = board->ai_range_type;
+
+ /* now check the user config option based on the boardtype */
if (board->is_818) {
- outb(0, dev->iobase + PCL818_RANGE);
+ if (it->options[4] == 1 || it->options[4] == 10) {
+ /* secondary range list jumper selectable */
+ s->range_table = &range_pcl818l_h_ai;
+ }
} else {
- outb(0, dev->iobase + PCL718_DA2_LO);
- outb(0, dev->iobase + PCL718_DA2_HI);
+ switch (it->options[4]) {
+ case 0:
+ s->range_table = &range_bipolar10;
+ break;
+ case 1:
+ s->range_table = &range_bipolar5;
+ break;
+ case 2:
+ s->range_table = &range_bipolar2_5;
+ break;
+ case 3:
+ s->range_table = &range718_bipolar1;
+ break;
+ case 4:
+ s->range_table = &range718_bipolar0_5;
+ break;
+ case 6:
+ s->range_table = &range_unipolar10;
+ break;
+ case 7:
+ s->range_table = &range_unipolar5;
+ break;
+ case 8:
+ s->range_table = &range718_unipolar2;
+ break;
+ case 9:
+ s->range_table = &range718_unipolar1;
+ break;
+ default:
+ s->range_table = &range_unknown;
+ break;
+ }
}
}
@@ -1215,182 +1083,96 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl818_board *board = comedi_board(dev);
struct pcl818_private *devpriv;
- int ret;
- unsigned int irq;
- int dma;
- unsigned long pages;
struct comedi_subdevice *s;
+ int ret;
+ int i;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- devpriv->io_range = board->io_range;
- if ((board->fifo) && (it->options[2] == -1)) {
- /* we've board with FIFO and we want to use FIFO */
- devpriv->io_range = PCLx1xFIFO_RANGE;
- devpriv->usefifo = 1;
- }
- ret = comedi_request_region(dev, it->options[0], devpriv->io_range);
+ ret = comedi_request_region(dev, it->options[0],
+ board->has_fifo ? 0x20 : 0x10);
if (ret)
return ret;
- if (pcl818_check(dev->iobase)) {
- comedi_error(dev, "I can't detect board. FAIL!\n");
- return -EIO;
+ /* we can use IRQ 2-7 for async command support */
+ if (it->options[1] >= 2 && it->options[1] <= 7) {
+ ret = request_irq(it->options[1], pcl818_interrupt, 0,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = it->options[1];
}
- /* grab our IRQ */
- irq = 0;
- if (board->IRQbits != 0) { /* board support IRQ */
- irq = it->options[1];
- if (irq) { /* we want to use IRQ */
- if (((1 << irq) & board->IRQbits) == 0) {
- printk
- (", IRQ %u is out of allowed range, DISABLING IT",
- irq);
- irq = 0; /* Bad IRQ */
- } else {
- if (request_irq(irq, interrupt_pcl818, 0,
- dev->board_name, dev)) {
- printk
- (", unable to allocate IRQ %u, DISABLING IT",
- irq);
- irq = 0; /* Can't use IRQ */
- } else {
- printk(KERN_DEBUG "irq=%u", irq);
- }
- }
+ /* should we use the FIFO? */
+ if (dev->irq && board->has_fifo && it->options[2] == -1)
+ devpriv->usefifo = 1;
+
+ /* we need an IRQ to do DMA on channel 3 or 1 */
+ if (dev->irq && board->has_dma &&
+ (it->options[2] == 3 || it->options[2] == 1)) {
+ ret = request_dma(it->options[2], dev->board_name);
+ if (ret) {
+ dev_err(dev->class_dev,
+ "unable to request DMA channel %d\n",
+ it->options[2]);
+ return -EBUSY;
}
- }
+ devpriv->dma = it->options[2];
- dev->irq = irq;
- if (irq)
- devpriv->irq_free = 1; /* 1=we have allocated irq */
- else
- devpriv->irq_free = 0;
-
- devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
- devpriv->ai_mode = 0; /* mode of irq */
-
- /* grab our DMA */
- dma = 0;
- devpriv->dma = dma;
- if (!devpriv->irq_free)
- goto no_dma; /* if we haven't IRQ, we can't use DMA */
- if (board->DMAbits != 0) { /* board support DMA */
- dma = it->options[2];
- if (dma < 1)
- goto no_dma; /* DMA disabled */
- if (((1 << dma) & board->DMAbits) == 0) {
- printk(KERN_ERR "DMA is out of allowed range, FAIL!\n");
- return -EINVAL; /* Bad DMA */
+ devpriv->dmapages = 2; /* we need 16KB */
+ devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
+
+ for (i = 0; i < 2; i++) {
+ unsigned long dmabuf;
+
+ dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
+ if (!dmabuf)
+ return -ENOMEM;
+
+ devpriv->dmabuf[i] = dmabuf;
+ devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
}
- ret = request_dma(dma, dev->board_name);
- if (ret)
- return -EBUSY; /* DMA isn't free */
- devpriv->dma = dma;
- pages = 2; /* we need 16KB */
- devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[0])
- /* maybe experiment with try_to_free_pages() will help .... */
- return -EBUSY; /* no buffer :-( */
- devpriv->dmapages[0] = pages;
- devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
- devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
- /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
- devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[1])
- return -EBUSY;
- devpriv->dmapages[1] = pages;
- devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
- devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
}
-no_dma:
-
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
return ret;
s = &dev->subdevices[0];
- if (!board->n_aichan_se) {
- s->type = COMEDI_SUBD_UNUSED;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE;
+ if (check_single_ended(dev->iobase)) {
+ s->n_chan = 16;
+ s->subdev_flags |= SDF_COMMON | SDF_GROUND;
} else {
- s->type = COMEDI_SUBD_AI;
- devpriv->sub_ai = s;
- s->subdev_flags = SDF_READABLE;
- if (check_single_ended(dev->iobase)) {
- s->n_chan = board->n_aichan_se;
- s->subdev_flags |= SDF_COMMON | SDF_GROUND;
- printk(", %dchans S.E. DAC", s->n_chan);
- } else {
- s->n_chan = board->n_aichan_diff;
- s->subdev_flags |= SDF_DIFF;
- printk(", %dchans DIFF DAC", s->n_chan);
- }
- s->maxdata = board->ai_maxdata;
- s->len_chanlist = s->n_chan;
- s->range_table = board->ai_range_type;
- s->cancel = pcl818_ai_cancel;
- s->insn_read = pcl818_ai_insn_read;
- if (irq) {
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->do_cmdtest = ai_cmdtest;
- s->do_cmd = ai_cmd;
- }
- if (board->is_818) {
- if ((it->options[4] == 1) || (it->options[4] == 10))
- s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */
- } else {
- switch (it->options[4]) {
- case 0:
- s->range_table = &range_bipolar10;
- break;
- case 1:
- s->range_table = &range_bipolar5;
- break;
- case 2:
- s->range_table = &range_bipolar2_5;
- break;
- case 3:
- s->range_table = &range718_bipolar1;
- break;
- case 4:
- s->range_table = &range718_bipolar0_5;
- break;
- case 6:
- s->range_table = &range_unipolar10;
- break;
- case 7:
- s->range_table = &range_unipolar5;
- break;
- case 8:
- s->range_table = &range718_unipolar2;
- break;
- case 9:
- s->range_table = &range718_unipolar1;
- break;
- default:
- s->range_table = &range_unknown;
- break;
- }
- }
+ s->n_chan = 8;
+ s->subdev_flags |= SDF_DIFF;
+ }
+ s->maxdata = 0x0fff;
+
+ pcl818_set_ai_range_table(dev, s, it);
+
+ s->insn_read = pcl818_ai_insn_read;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = s->n_chan;
+ s->do_cmdtest = ai_cmdtest;
+ s->do_cmd = pcl818_ai_cmd;
+ s->cancel = pcl818_ai_cancel;
}
+ /* Analog Output subdevice */
s = &dev->subdevices[1];
- if (!board->n_aochan) {
- s->type = COMEDI_SUBD_UNUSED;
- } else {
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
- s->n_chan = board->n_aochan;
- s->maxdata = board->ao_maxdata;
- s->len_chanlist = board->n_aochan;
- s->range_table = board->ao_range_type;
- s->insn_read = pcl818_ao_insn_read;
- s->insn_write = pcl818_ao_insn_write;
+ if (board->n_aochan) {
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
+ s->n_chan = board->n_aochan;
+ s->maxdata = 0x0fff;
+ s->range_table = &range_unipolar5;
+ s->insn_read = pcl818_ao_insn_read;
+ s->insn_write = pcl818_ao_insn_write;
if (board->is_818) {
if ((it->options[4] == 1) || (it->options[4] == 10))
s->range_table = &range_unipolar10;
@@ -1402,33 +1184,27 @@ no_dma:
if (it->options[5] == 2)
s->range_table = &range_unknown;
}
- }
-
- s = &dev->subdevices[2];
- if (!board->n_dichan) {
- s->type = COMEDI_SUBD_UNUSED;
} else {
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = board->n_dichan;
- s->maxdata = 1;
- s->len_chanlist = board->n_dichan;
- s->range_table = &range_digital;
- s->insn_bits = pcl818_di_insn_bits;
+ s->type = COMEDI_SUBD_UNUSED;
}
+ /* 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->range_table = &range_digital;
+ s->insn_bits = pcl818_di_insn_bits;
+
+ /* Digital Output subdevice */
s = &dev->subdevices[3];
- if (!board->n_dochan) {
- s->type = COMEDI_SUBD_UNUSED;
- } else {
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = board->n_dochan;
- s->maxdata = 1;
- s->len_chanlist = board->n_dochan;
- s->range_table = &range_digital;
- s->insn_bits = pcl818_do_insn_bits;
- }
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcl818_do_insn_bits;
/* select 1/10MHz oscilator */
if ((it->options[3] == 0) || (it->options[3] == 10))
@@ -1446,8 +1222,6 @@ no_dma:
pcl818_reset(dev);
- printk("\n");
-
return 0;
}
@@ -1456,43 +1230,18 @@ static void pcl818_detach(struct comedi_device *dev)
struct pcl818_private *devpriv = dev->private;
if (devpriv) {
- pcl818_ai_cancel(dev, devpriv->sub_ai);
+ pcl818_ai_cancel(dev, dev->read_subdev);
pcl818_reset(dev);
if (devpriv->dma)
free_dma(devpriv->dma);
if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
+ free_pages(devpriv->dmabuf[0], devpriv->dmapages);
if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
+ free_pages(devpriv->dmabuf[1], devpriv->dmapages);
}
comedi_legacy_detach(dev);
}
-static const struct pcl818_board boardtypes[] = {
- {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1},
- {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1},
- {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 1, 1},
- {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 1, 1},
- {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1},
- {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 0},
- /* pcm3718 */
- {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
-};
-
static struct comedi_driver pcl818_driver = {
.driver_name = "pcl818",
.module = THIS_MODULE,
diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c
index cc1dc7f66e5..53e73737a90 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -70,14 +70,11 @@ static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
{
unsigned long iobase = arg;
unsigned char inbres;
- /* printk("8255cb %d %d %d %lx\n", dir,port,data,arg); */
if (dir) {
- /* printk("8255 cb outb(%x, %lx)\n", data, iobase+port); */
outb(data, iobase + port);
return 0;
} else {
inbres = inb(iobase + port);
- /* printk("8255 cb inb(%lx) = %x\n", iobase+port, inbres); */
return inbres;
}
}
@@ -137,8 +134,6 @@ static void do_3724_config(struct comedi_device *dev,
port_8255_cfg = dev->iobase + SIZE_8255 + _8255_CR;
outb(buffer_config, dev->iobase + 8); /* update buffer register */
- /* printk("pcm3724 buffer_config (%lx) %d, %x\n",
- dev->iobase + _8255_CR, chanspec, buffer_config); */
outb(config, port_8255_cfg);
}
@@ -177,7 +172,6 @@ static void enable_chan(struct comedi_device *dev, struct comedi_subdevice *s,
if (priv->dio_2 & 0xff)
gatecfg |= GATE_A1;
- /* printk("gate control %x\n", gatecfg); */
outb(gatecfg, dev->iobase + 9);
}
@@ -231,8 +225,10 @@ static int pcm3724_attach(struct comedi_device *dev,
for (i = 0; i < dev->n_subdevices; i++) {
s = &dev->subdevices[i];
- subdev_8255_init(dev, s, subdev_8255_cb,
- (unsigned long)(dev->iobase + SIZE_8255 * i));
+ ret = subdev_8255_init(dev, s, subdev_8255_cb,
+ dev->iobase + SIZE_8255 * i);
+ if (ret)
+ return ret;
s->insn_config = subdev_3724_insn_config;
}
return 0;
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index fe482fdd512..87c61d9b11d 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -61,18 +61,17 @@ static const struct pcmad_board_struct pcmad_boards[] = {
},
};
-#define TIMEOUT 100
-
-static int pcmad_ai_wait_for_eoc(struct comedi_device *dev,
- int timeout)
+static int pcmad_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- int i;
+ unsigned int status;
- for (i = 0; i < timeout; i++) {
- if ((inb(dev->iobase + PCMAD_STATUS) & 0x3) == 0x3)
- return 0;
- }
- return -ETIME;
+ status = inb(dev->iobase + PCMAD_STATUS);
+ if ((status & 0x3) == 0x3)
+ return 0;
+ return -EBUSY;
}
static int pcmad_ai_insn_read(struct comedi_device *dev,
@@ -89,7 +88,7 @@ static int pcmad_ai_insn_read(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
outb(chan, dev->iobase + PCMAD_CONVERT);
- ret = pcmad_ai_wait_for_eoc(dev, TIMEOUT);
+ ret = comedi_timeout(dev, s, insn, pcmad_ai_eoc, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index 14cee3ac92c..fed7e77e030 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -1,76 +1,76 @@
/*
- comedi/drivers/pcmmio.c
- Driver for Winsystems PC-104 based multifunction IO board.
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 2007 Calin A. Culianu <calin@ajvar.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.
-*/
+ * pcmmio.c
+ * Driver for Winsystems PC-104 based multifunction IO board.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2007 Calin A. Culianu <calin@ajvar.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: pcmmio
-Description: A driver for the PCM-MIO multifunction board
-Devices: [Winsystems] PCM-MIO (pcmmio)
-Author: Calin Culianu <calin@ajvar.org>
-Updated: Wed, May 16 2007 16:21:10 -0500
-Status: works
-
-A driver for the relatively new PCM-MIO multifunction board from
-Winsystems. This board is a PC-104 based I/O board. It contains
-four subdevices:
- subdevice 0 - 16 channels of 16-bit AI
- subdevice 1 - 8 channels of 16-bit AO
- subdevice 2 - first 24 channels of the 48 channel of DIO
- (with edge-triggered interrupt support)
- subdevice 3 - last 24 channels of the 48 channel DIO
- (no interrupt support for this bank of channels)
-
- Some notes:
-
- Synchronous reads and writes are the only things implemented for AI and AO,
- even though the hardware itself can do streaming acquisition, etc. Anyone
- want to add asynchronous I/O for AI/AO as a feature? Be my guest...
-
- Asynchronous I/O for the DIO subdevices *is* implemented, however! They are
- basically edge-triggered interrupts for any configuration of the first
- 24 DIO-lines.
-
- Also note that this interrupt support is untested.
-
- A few words about edge-detection IRQ support (commands on DIO):
-
- * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
- of the board to the comedi_config command. The board IRQ is not jumpered
- but rather configured through software, so any IRQ from 1-15 is OK.
-
- * Due to the genericity of the comedi API, you need to create a special
- comedi_command in order to use edge-triggered interrupts for DIO.
-
- * Use comedi_commands with TRIG_NOW. Your callback will be called each
- time an edge is detected on the specified DIO line(s), and the data
- values will be two sample_t's, which should be concatenated to form
- one 32-bit unsigned int. This value is the mask of channels that had
- edges detected from your channel list. Note that the bits positions
- in the mask correspond to positions in your chanlist when you
- specified the command and *not* channel id's!
-
- * To set the polarity of the edge-detection interrupts pass a nonzero value
- for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
- value for both CR_RANGE and CR_AREF if you want edge-down polarity.
-
-Configuration Options:
- [0] - I/O port base address
- [1] - IRQ (optional -- for edge-detect interrupt support only,
- leave out if you don't need this feature)
-*/
+ * Driver: pcmmio
+ * Description: A driver for the PCM-MIO multifunction board
+ * Devices: (Winsystems) PCM-MIO [pcmmio]
+ * Author: Calin Culianu <calin@ajvar.org>
+ * Updated: Wed, May 16 2007 16:21:10 -0500
+ * Status: works
+ *
+ * A driver for the PCM-MIO multifunction board from Winsystems. This
+ * is a PC-104 based I/O board. It contains four subdevices:
+ *
+ * subdevice 0 - 16 channels of 16-bit AI
+ * subdevice 1 - 8 channels of 16-bit AO
+ * subdevice 2 - first 24 channels of the 48 channel of DIO
+ * (with edge-triggered interrupt support)
+ * subdevice 3 - last 24 channels of the 48 channel DIO
+ * (no interrupt support for this bank of channels)
+ *
+ * Some notes:
+ *
+ * Synchronous reads and writes are the only things implemented for analog
+ * input and output. The hardware itself can do streaming acquisition, etc.
+ *
+ * Asynchronous I/O for the DIO subdevices *is* implemented, however! They
+ * are basically edge-triggered interrupts for any configuration of the
+ * channels in subdevice 2.
+ *
+ * Also note that this interrupt support is untested.
+ *
+ * A few words about edge-detection IRQ support (commands on DIO):
+ *
+ * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
+ * of the board to the comedi_config command. The board IRQ is not jumpered
+ * but rather configured through software, so any IRQ from 1-15 is OK.
+ *
+ * Due to the genericity of the comedi API, you need to create a special
+ * comedi_command in order to use edge-triggered interrupts for DIO.
+ *
+ * Use comedi_commands with TRIG_NOW. Your callback will be called each
+ * time an edge is detected on the specified DIO line(s), and the data
+ * values will be two sample_t's, which should be concatenated to form
+ * one 32-bit unsigned int. This value is the mask of channels that had
+ * edges detected from your channel list. Note that the bits positions
+ * in the mask correspond to positions in your chanlist when you
+ * specified the command and *not* channel id's!
+ *
+ * To set the polarity of the edge-detection interrupts pass a nonzero value
+ * for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
+ * value for both CR_RANGE and CR_AREF if you want edge-down polarity.
+ *
+ * Configuration Options:
+ * [0] - I/O port base address
+ * [1] - IRQ (optional -- for edge-detect interrupt support only,
+ * leave out if you don't need this feature)
+ */
#include <linux/module.h>
#include <linux/interrupt.h>
@@ -80,232 +80,210 @@ Configuration Options:
#include "comedi_fc.h"
-/* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
-#define CHANS_PER_PORT 8
-#define PORTS_PER_ASIC 6
-#define INTR_PORTS_PER_ASIC 3
-#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */
-#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
-#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
-#define INTR_CHANS_PER_ASIC 24
-#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
-#define MAX_DIO_CHANS (PORTS_PER_ASIC*1*CHANS_PER_PORT)
-#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC)
-#define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
-/* IO Memory sizes */
-#define ASIC_IOSIZE (0x0B)
-#define PCMMIO48_IOSIZE ASIC_IOSIZE
-
-/* Some offsets - these are all in the 16byte IO memory offset from
- the base address. Note that there is a paging scheme to swap out
- offsets 0x8-0xA using the PAGELOCK register. See the table below.
-
- Register(s) Pages R/W? Description
- --------------------------------------------------------------
- REG_PORTx All R/W Read/Write/Configure IO
- REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int.
- REG_PAGELOCK All WriteOnly Select a page
- REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity
- REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int.
- REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints.
+/*
+ * Register I/O map
*/
-#define REG_PORT0 0x0
-#define REG_PORT1 0x1
-#define REG_PORT2 0x2
-#define REG_PORT3 0x3
-#define REG_PORT4 0x4
-#define REG_PORT5 0x5
-#define REG_INT_PENDING 0x6
-#define REG_PAGELOCK 0x7 /*
- * page selector register, upper 2 bits select
- * a page and bits 0-5 are used to 'lock down'
- * a particular port above to make it readonly.
- */
-#define REG_POL0 0x8
-#define REG_POL1 0x9
-#define REG_POL2 0xA
-#define REG_ENAB0 0x8
-#define REG_ENAB1 0x9
-#define REG_ENAB2 0xA
-#define REG_INT_ID0 0x8
-#define REG_INT_ID1 0x9
-#define REG_INT_ID2 0xA
-
-#define NUM_PAGED_REGS 3
-#define NUM_PAGES 4
-#define FIRST_PAGED_REG 0x8
-#define REG_PAGE_BITOFFSET 6
-#define REG_LOCK_BITOFFSET 0
-#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
-#define REG_LOCK_MASK (~(REG_PAGE_MASK))
-#define PAGE_POL 1
-#define PAGE_ENAB 2
-#define PAGE_INT_ID 3
-
-static const struct comedi_lrange ranges_ai = {
- 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)}
-};
+#define PCMMIO_AI_LSB_REG 0x00
+#define PCMMIO_AI_MSB_REG 0x01
+#define PCMMIO_AI_CMD_REG 0x02
+#define PCMMIO_AI_CMD_SE (1 << 7)
+#define PCMMIO_AI_CMD_ODD_CHAN (1 << 6)
+#define PCMMIO_AI_CMD_CHAN_SEL(x) (((x) & 0x3) << 4)
+#define PCMMIO_AI_CMD_RANGE(x) (((x) & 0x3) << 2)
+#define PCMMIO_RESOURCE_REG 0x02
+#define PCMMIO_RESOURCE_IRQ(x) (((x) & 0xf) << 0)
+#define PCMMIO_AI_STATUS_REG 0x03
+#define PCMMIO_AI_STATUS_DATA_READY (1 << 7)
+#define PCMMIO_AI_STATUS_DATA_DMA_PEND (1 << 6)
+#define PCMMIO_AI_STATUS_CMD_DMA_PEND (1 << 5)
+#define PCMMIO_AI_STATUS_IRQ_PEND (1 << 4)
+#define PCMMIO_AI_STATUS_DATA_DRQ_ENA (1 << 2)
+#define PCMMIO_AI_STATUS_REG_SEL (1 << 3)
+#define PCMMIO_AI_STATUS_CMD_DRQ_ENA (1 << 1)
+#define PCMMIO_AI_STATUS_IRQ_ENA (1 << 0)
+#define PCMMIO_AI_RES_ENA_REG 0x03
+#define PCMMIO_AI_RES_ENA_CMD_REG_ACCESS (0 << 3)
+#define PCMMIO_AI_RES_ENA_AI_RES_ACCESS (1 << 3)
+#define PCMMIO_AI_RES_ENA_DIO_RES_ACCESS (1 << 4)
+#define PCMMIO_AI_2ND_ADC_OFFSET 0x04
+
+#define PCMMIO_AO_LSB_REG 0x08
+#define PCMMIO_AO_LSB_SPAN(x) (((x) & 0xf) << 0)
+#define PCMMIO_AO_MSB_REG 0x09
+#define PCMMIO_AO_CMD_REG 0x0a
+#define PCMMIO_AO_CMD_WR_SPAN (0x2 << 4)
+#define PCMMIO_AO_CMD_WR_CODE (0x3 << 4)
+#define PCMMIO_AO_CMD_UPDATE (0x4 << 4)
+#define PCMMIO_AO_CMD_UPDATE_ALL (0x5 << 4)
+#define PCMMIO_AO_CMD_WR_SPAN_UPDATE (0x6 << 4)
+#define PCMMIO_AO_CMD_WR_CODE_UPDATE (0x7 << 4)
+#define PCMMIO_AO_CMD_WR_SPAN_UPDATE_ALL (0x8 << 4)
+#define PCMMIO_AO_CMD_WR_CODE_UPDATE_ALL (0x9 << 4)
+#define PCMMIO_AO_CMD_RD_B1_SPAN (0xa << 4)
+#define PCMMIO_AO_CMD_RD_B1_CODE (0xb << 4)
+#define PCMMIO_AO_CMD_RD_B2_SPAN (0xc << 4)
+#define PCMMIO_AO_CMD_RD_B2_CODE (0xd << 4)
+#define PCMMIO_AO_CMD_NOP (0xf << 4)
+#define PCMMIO_AO_CMD_CHAN_SEL(x) (((x) & 0x03) << 1)
+#define PCMMIO_AO_CMD_CHAN_SEL_ALL (0x0f << 0)
+#define PCMMIO_AO_STATUS_REG 0x0b
+#define PCMMIO_AO_STATUS_DATA_READY (1 << 7)
+#define PCMMIO_AO_STATUS_DATA_DMA_PEND (1 << 6)
+#define PCMMIO_AO_STATUS_CMD_DMA_PEND (1 << 5)
+#define PCMMIO_AO_STATUS_IRQ_PEND (1 << 4)
+#define PCMMIO_AO_STATUS_DATA_DRQ_ENA (1 << 2)
+#define PCMMIO_AO_STATUS_REG_SEL (1 << 3)
+#define PCMMIO_AO_STATUS_CMD_DRQ_ENA (1 << 1)
+#define PCMMIO_AO_STATUS_IRQ_ENA (1 << 0)
+#define PCMMIO_AO_RESOURCE_ENA_REG 0x0b
+#define PCMMIO_AO_2ND_DAC_OFFSET 0x04
-static const struct comedi_lrange ranges_ao = {
- 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
- RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
+/*
+ * WinSystems WS16C48
+ *
+ * Offset Page 0 Page 1 Page 2 Page 3
+ * ------ ----------- ----------- ----------- -----------
+ * 0x10 Port 0 I/O Port 0 I/O Port 0 I/O Port 0 I/O
+ * 0x11 Port 1 I/O Port 1 I/O Port 1 I/O Port 1 I/O
+ * 0x12 Port 2 I/O Port 2 I/O Port 2 I/O Port 2 I/O
+ * 0x13 Port 3 I/O Port 3 I/O Port 3 I/O Port 3 I/O
+ * 0x14 Port 4 I/O Port 4 I/O Port 4 I/O Port 4 I/O
+ * 0x15 Port 5 I/O Port 5 I/O Port 5 I/O Port 5 I/O
+ * 0x16 INT_PENDING INT_PENDING INT_PENDING INT_PENDING
+ * 0x17 Page/Lock Page/Lock Page/Lock Page/Lock
+ * 0x18 N/A POL_0 ENAB_0 INT_ID0
+ * 0x19 N/A POL_1 ENAB_1 INT_ID1
+ * 0x1a N/A POL_2 ENAB_2 INT_ID2
+ */
+#define PCMMIO_PORT_REG(x) (0x10 + (x))
+#define PCMMIO_INT_PENDING_REG 0x16
+#define PCMMIO_PAGE_LOCK_REG 0x17
+#define PCMMIO_LOCK_PORT(x) ((1 << (x)) & 0x3f)
+#define PCMMIO_PAGE(x) (((x) & 0x3) << 6)
+#define PCMMIO_PAGE_MASK PCMUIO_PAGE(3)
+#define PCMMIO_PAGE_POL 1
+#define PCMMIO_PAGE_ENAB 2
+#define PCMMIO_PAGE_INT_ID 3
+#define PCMMIO_PAGE_REG(x) (0x18 + (x))
+
+static const struct comedi_lrange pcmmio_ai_ranges = {
+ 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(10)
+ }
};
-/* this structure is for data unique to this subdevice. */
-struct pcmmio_subdev_private {
-
- union {
- /* for DIO: mapping of halfwords (bytes)
- in port/chanarray to iobase */
- unsigned long iobases[PORTS_PER_SUBDEV];
-
- /* for AI/AO */
- unsigned long iobase;
- };
- union {
- struct {
-
- /* The below is only used for intr subdevices */
- struct {
- /*
- * if non-negative, this subdev has an
- * interrupt asic
- */
- int asic;
- /*
- * if nonnegative, the first channel id for
- * interrupts.
- */
- int first_chan;
- /*
- * the number of asic channels in this subdev
- * that have interrutps
- */
- int num_asic_chans;
- /*
- * if nonnegative, the first channel id with
- * respect to the asic that has interrupts
- */
- int asic_chan;
- /*
- * subdev-relative channel mask for channels
- * we are interested in
- */
- int enabled_mask;
- int active;
- int stop_count;
- int continuous;
- spinlock_t spinlock;
- } intr;
- } dio;
- struct {
- /* the last unsigned int data written */
- unsigned int shadow_samples[8];
- } ao;
- };
+static const struct comedi_lrange pcmmio_ao_ranges = {
+ 6, {
+ UNI_RANGE(5),
+ UNI_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ BIP_RANGE(2.5),
+ RANGE(-2.5, 7.5)
+ }
};
-/*
- * this structure is for data unique to this hardware driver. If
- * several hardware drivers keep similar information in this structure,
- * feel free to suggest moving the variable to the struct comedi_device struct.
- */
struct pcmmio_private {
- /* stuff for DIO */
- struct {
- unsigned char pagelock; /* current page and lock */
- /* shadow of POLx registers */
- unsigned char pol[NUM_PAGED_REGS];
- /* shadow of ENABx registers */
- unsigned char enab[NUM_PAGED_REGS];
- int num;
- unsigned long iobase;
- unsigned int irq;
- spinlock_t spinlock;
- } asics[MAX_ASICS];
- struct pcmmio_subdev_private *sprivs;
+ spinlock_t pagelock; /* protects the page registers */
+ spinlock_t spinlock; /* protects the member variables */
+ unsigned int enabled_mask;
+ unsigned int stop_count;
+ unsigned int active:1;
+
+ unsigned int ao_readback[8];
};
-#define subpriv ((struct pcmmio_subdev_private *)s->private)
+static void pcmmio_dio_write(struct comedi_device *dev, unsigned int val,
+ int page, int port)
+{
+ struct pcmmio_private *devpriv = dev->private;
+ unsigned long iobase = dev->iobase;
+ unsigned long flags;
+
+ spin_lock_irqsave(&devpriv->pagelock, flags);
+ if (page == 0) {
+ /* Port registers are valid for any page */
+ outb(val & 0xff, iobase + PCMMIO_PORT_REG(port + 0));
+ outb((val >> 8) & 0xff, iobase + PCMMIO_PORT_REG(port + 1));
+ outb((val >> 16) & 0xff, iobase + PCMMIO_PORT_REG(port + 2));
+ } else {
+ outb(PCMMIO_PAGE(page), iobase + PCMMIO_PAGE_LOCK_REG);
+ outb(val & 0xff, iobase + PCMMIO_PAGE_REG(0));
+ outb((val >> 8) & 0xff, iobase + PCMMIO_PAGE_REG(1));
+ outb((val >> 16) & 0xff, iobase + PCMMIO_PAGE_REG(2));
+ }
+ spin_unlock_irqrestore(&devpriv->pagelock, flags);
+}
+
+static unsigned int pcmmio_dio_read(struct comedi_device *dev,
+ int page, int port)
+{
+ struct pcmmio_private *devpriv = dev->private;
+ unsigned long iobase = dev->iobase;
+ unsigned long flags;
+ unsigned int val;
+
+ spin_lock_irqsave(&devpriv->pagelock, flags);
+ if (page == 0) {
+ /* Port registers are valid for any page */
+ val = inb(iobase + PCMMIO_PORT_REG(port + 0));
+ val |= (inb(iobase + PCMMIO_PORT_REG(port + 1)) << 8);
+ val |= (inb(iobase + PCMMIO_PORT_REG(port + 2)) << 16);
+ } else {
+ outb(PCMMIO_PAGE(page), iobase + PCMMIO_PAGE_LOCK_REG);
+ val = inb(iobase + PCMMIO_PAGE_REG(0));
+ val |= (inb(iobase + PCMMIO_PAGE_REG(1)) << 8);
+ val |= (inb(iobase + PCMMIO_PAGE_REG(2)) << 16);
+ }
+ spin_unlock_irqrestore(&devpriv->pagelock, flags);
+
+ return val;
+}
-/* DIO devices are slightly special. Although it is possible to
- * implement the insn_read/insn_write interface, it is much more
- * useful to applications if you implement the insn_bits interface.
- * This allows packed reading/writing of the DIO channels. The
- * comedi core can convert between insn_bits and insn_read/write */
+/*
+ * Each channel can be individually programmed for input or output.
+ * Writing a '0' to a channel causes the corresponding output pin
+ * to go to a high-z state (pulled high by an external 10K resistor).
+ * This allows it to be used as an input. When used in the input mode,
+ * a read reflects the inverted state of the I/O pin, such that a
+ * high on the pin will read as a '0' in the register. Writing a '1'
+ * to a bit position causes the pin to sink current (up to 12mA),
+ * effectively pulling it low.
+ */
static int pcmmio_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int byte_no;
-
- /* NOTE:
- reading a 0 means this channel was high
- writine a 0 sets the channel high
- reading a 1 means this channel was low
- writing a 1 means set this channel low
-
- Therefore everything is always inverted. */
-
- /* The insn data is a mask in data[0] and the new data
- * in data[1], each channel cooresponding to a bit. */
-
-#ifdef DAMMIT_ITS_BROKEN
- /* DEBUG */
- printk(KERN_DEBUG "write mask: %08x data: %08x\n", data[0], data[1]);
-#endif
-
- s->state = 0;
-
- for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
- /* address of 8-bit port */
- unsigned long ioaddr = subpriv->iobases[byte_no],
- /* bit offset of port in 32-bit doubleword */
- offset = byte_no * 8;
- /* this 8-bit port's data */
- unsigned char byte = 0,
- /* The write mask for this port (if any) */
- write_mask_byte = (data[0] >> offset) & 0xff,
- /* The data byte for this port */
- data_byte = (data[1] >> offset) & 0xff;
-
- byte = inb(ioaddr); /* read all 8-bits for this port */
-
-#ifdef DAMMIT_ITS_BROKEN
- /* DEBUG */
- printk
- (KERN_DEBUG "byte %d wmb %02x db %02x offset %02d io %04x,"
- " data_in %02x ", byte_no, (unsigned)write_mask_byte,
- (unsigned)data_byte, offset, ioaddr, (unsigned)byte);
-#endif
-
- if (write_mask_byte) {
- /*
- * this byte has some write_bits
- * -- so set the output lines
- */
- /* clear bits for write mask */
- byte &= ~write_mask_byte;
- /* set to inverted data_byte */
- byte |= ~data_byte & write_mask_byte;
- /* Write out the new digital output state */
- outb(byte, ioaddr);
- }
-#ifdef DAMMIT_ITS_BROKEN
- /* DEBUG */
- printk(KERN_DEBUG "data_out_byte %02x\n", (unsigned)byte);
-#endif
- /* save the digital input lines for this byte.. */
- s->state |= ((unsigned int)byte) << offset;
+ /* subdevice 2 uses ports 0-2, subdevice 3 uses ports 3-5 */
+ int port = s->index == 2 ? 0 : 3;
+ unsigned int chanmask = (1 << s->n_chan) - 1;
+ unsigned int mask;
+ unsigned int val;
+
+ mask = comedi_dio_update_state(s, data);
+ if (mask) {
+ /*
+ * Outputs are inverted, invert the state and
+ * update the channels.
+ *
+ * The s->io_bits mask makes sure the input channels
+ * are '0' so that the outputs pins stay in a high
+ * z-state.
+ */
+ val = ~s->state & chanmask;
+ val &= s->io_bits;
+ pcmmio_dio_write(dev, val, 0, port);
}
- /* now return the DIO lines to data[1] - note they came inverted! */
- data[1] = ~s->state;
+ /* get inverted state of the channels from the port */
+ val = pcmmio_dio_read(dev, 0, port);
-#ifdef DAMMIT_ITS_BROKEN
- /* DEBUG */
- printk(KERN_DEBUG "s->state %08x data_out %08x\n", s->state, data[1]);
-#endif
+ /* return the true state of the channels */
+ data[1] = ~val & chanmask;
return insn->n;
}
@@ -315,398 +293,190 @@ static int pcmmio_dio_insn_config(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- unsigned int chan = CR_CHAN(insn->chanspec);
- int byte_no = chan / 8;
- int bit_no = chan % 8;
+ /* subdevice 2 uses ports 0-2, subdevice 3 uses ports 3-5 */
+ int port = s->index == 2 ? 0 : 3;
int ret;
ret = comedi_dio_insn_config(dev, s, insn, data, 0);
if (ret)
return ret;
- if (data[0] == INSN_CONFIG_DIO_INPUT) {
- unsigned long ioaddr = subpriv->iobases[byte_no];
- unsigned char val;
-
- val = inb(ioaddr);
- val &= ~(1 << bit_no);
- outb(val, ioaddr);
- }
+ if (data[0] == INSN_CONFIG_DIO_INPUT)
+ pcmmio_dio_write(dev, s->io_bits, 0, port);
return insn->n;
}
-static void switch_page(struct comedi_device *dev, int asic, int page)
+static void pcmmio_reset(struct comedi_device *dev)
{
- struct pcmmio_private *devpriv = dev->private;
-
- if (asic < 0 || asic >= 1)
- return; /* paranoia */
- if (page < 0 || page >= NUM_PAGES)
- return; /* more paranoia */
-
- devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
- devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
-
- /* now write out the shadow register */
- outb(devpriv->asics[asic].pagelock,
- devpriv->asics[asic].iobase + REG_PAGELOCK);
+ /* Clear all the DIO port bits */
+ pcmmio_dio_write(dev, 0, 0, 0);
+ pcmmio_dio_write(dev, 0, 0, 3);
+
+ /* Clear all the paged registers */
+ pcmmio_dio_write(dev, 0, PCMMIO_PAGE_POL, 0);
+ pcmmio_dio_write(dev, 0, PCMMIO_PAGE_ENAB, 0);
+ pcmmio_dio_write(dev, 0, PCMMIO_PAGE_INT_ID, 0);
}
-static void init_asics(struct comedi_device *dev)
-{ /* sets up an
- ASIC chip to defaults */
+/* devpriv->spinlock is already locked */
+static void pcmmio_stop_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
struct pcmmio_private *devpriv = dev->private;
- int asic;
-
- for (asic = 0; asic < 1; ++asic) {
- int port, page;
- unsigned long baseaddr = devpriv->asics[asic].iobase;
-
- switch_page(dev, asic, 0); /* switch back to page 0 */
-
- /* first, clear all the DIO port bits */
- for (port = 0; port < PORTS_PER_ASIC; ++port)
- outb(0, baseaddr + REG_PORT0 + port);
-
- /* Next, clear all the paged registers for each page */
- for (page = 1; page < NUM_PAGES; ++page) {
- int reg;
- /* now clear all the paged registers */
- switch_page(dev, asic, page);
- for (reg = FIRST_PAGED_REG;
- reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
- outb(0, baseaddr + reg);
- }
- /* DEBUG set rising edge interrupts on port0 of both asics */
- /*switch_page(dev, asic, PAGE_POL);
- outb(0xff, baseaddr + REG_POL0);
- switch_page(dev, asic, PAGE_ENAB);
- outb(0xff, baseaddr + REG_ENAB0); */
- /* END DEBUG */
+ devpriv->enabled_mask = 0;
+ devpriv->active = 0;
+ s->async->inttrig = NULL;
- /* switch back to default page 0 */
- switch_page(dev, asic, 0);
- }
+ /* disable all dio interrupts */
+ pcmmio_dio_write(dev, 0, PCMMIO_PAGE_ENAB, 0);
}
-#ifdef notused
-static void lock_port(struct comedi_device *dev, int asic, int port)
+static void pcmmio_handle_dio_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int triggered)
{
struct pcmmio_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int oldevents = s->async->events;
+ unsigned int val = 0;
+ unsigned long flags;
+ int i;
- if (asic < 0 || asic >= 1)
- return; /* paranoia */
- if (port < 0 || port >= PORTS_PER_ASIC)
- return; /* more paranoia */
+ spin_lock_irqsave(&devpriv->spinlock, flags);
- devpriv->asics[asic].pagelock |= 0x1 << port;
- /* now write out the shadow register */
- outb(devpriv->asics[asic].pagelock,
- devpriv->asics[asic].iobase + REG_PAGELOCK);
- return;
-}
+ if (!devpriv->active)
+ goto done;
-static void unlock_port(struct comedi_device *dev, int asic, int port)
-{
- struct pcmmio_private *devpriv = dev->private;
+ if (!(triggered & devpriv->enabled_mask))
+ goto done;
- if (asic < 0 || asic >= 1)
- return; /* paranoia */
- if (port < 0 || port >= PORTS_PER_ASIC)
- return; /* more paranoia */
- devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
- /* now write out the shadow register */
- outb(devpriv->asics[asic].pagelock,
- devpriv->asics[asic].iobase + REG_PAGELOCK);
-}
-#endif /* notused */
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
-static void pcmmio_stop_intr(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pcmmio_private *devpriv = dev->private;
- int nports, firstport, asic, port;
+ if (triggered & (1 << chan))
+ val |= (1 << i);
+ }
- asic = subpriv->dio.intr.asic;
- if (asic < 0)
- return; /* not an interrupt subdev */
+ /* Write the scan to the buffer. */
+ if (comedi_buf_put(s, val) &&
+ comedi_buf_put(s, val >> 16)) {
+ s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
+ } else {
+ /* Overflow! Stop acquisition!! */
+ /* TODO: STOP_ACQUISITION_CALL_HERE!! */
+ pcmmio_stop_intr(dev, s);
+ }
- subpriv->dio.intr.enabled_mask = 0;
- subpriv->dio.intr.active = 0;
- s->async->inttrig = NULL;
- nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
- firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
- switch_page(dev, asic, PAGE_ENAB);
- for (port = firstport; port < firstport + nports; ++port) {
- /* disable all intrs for this subdev.. */
- outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
+ /* Check for end of acquisition. */
+ if (cmd->stop_src == TRIG_COUNT && devpriv->stop_count > 0) {
+ devpriv->stop_count--;
+ if (devpriv->stop_count == 0) {
+ s->async->events |= COMEDI_CB_EOA;
+ /* TODO: STOP_ACQUISITION_CALL_HERE!! */
+ pcmmio_stop_intr(dev, s);
+ }
}
+
+done:
+ spin_unlock_irqrestore(&devpriv->spinlock, flags);
+
+ if (oldevents != s->async->events)
+ comedi_event(dev, s);
}
static irqreturn_t interrupt_pcmmio(int irq, void *d)
{
- int asic, got1 = 0;
- struct comedi_device *dev = (struct comedi_device *)d;
- struct pcmmio_private *devpriv = dev->private;
- int i;
+ struct comedi_device *dev = d;
+ struct comedi_subdevice *s = dev->read_subdev;
+ unsigned int triggered;
+ unsigned char int_pend;
- for (asic = 0; asic < MAX_ASICS; ++asic) {
- if (irq == devpriv->asics[asic].irq) {
- unsigned long flags;
- unsigned triggered = 0;
- unsigned long iobase = devpriv->asics[asic].iobase;
- /* it is an interrupt for ASIC #asic */
- unsigned char int_pend;
-
- spin_lock_irqsave(&devpriv->asics[asic].spinlock,
- flags);
-
- int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
-
- if (int_pend) {
- int port;
- for (port = 0; port < INTR_PORTS_PER_ASIC;
- ++port) {
- if (int_pend & (0x1 << port)) {
- unsigned char
- io_lines_with_edges = 0;
- switch_page(dev, asic,
- PAGE_INT_ID);
- io_lines_with_edges =
- inb(iobase +
- REG_INT_ID0 + port);
-
- if (io_lines_with_edges)
- /*
- * clear pending
- * interrupt
- */
- outb(0, iobase +
- REG_INT_ID0 +
- port);
-
- triggered |=
- io_lines_with_edges <<
- port * 8;
- }
- }
-
- ++got1;
- }
-
- spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
- flags);
-
- if (triggered) {
- struct comedi_subdevice *s;
- /*
- * TODO here: dispatch io lines to subdevs
- * with commands..
- */
- printk
- (KERN_DEBUG "got edge detect interrupt %d asic %d which_chans: %06x\n",
- irq, asic, triggered);
- for (i = 2; i < dev->n_subdevices; i++) {
- s = &dev->subdevices[i];
- /*
- * this is an interrupt subdev,
- * and it matches this asic!
- */
- if (subpriv->dio.intr.asic == asic) {
- unsigned long flags;
- unsigned oldevents;
-
- spin_lock_irqsave(&subpriv->dio.
- intr.spinlock,
- flags);
-
- oldevents = s->async->events;
-
- if (subpriv->dio.intr.active) {
- unsigned mytrig =
- ((triggered >>
- subpriv->dio.intr.asic_chan)
- &
- ((0x1 << subpriv->
- dio.intr.
- num_asic_chans) -
- 1)) << subpriv->
- dio.intr.first_chan;
- if (mytrig &
- subpriv->dio.
- intr.enabled_mask) {
- unsigned int val
- = 0;
- unsigned int n,
- ch, len;
-
- len =
- s->
- async->cmd.chanlist_len;
- for (n = 0;
- n < len;
- n++) {
- ch = CR_CHAN(s->async->cmd.chanlist[n]);
- if (mytrig & (1U << ch))
- val |= (1U << n);
- }
- /* Write the scan to the buffer. */
- if (comedi_buf_put(s->async, val)
- &&
- comedi_buf_put
- (s->async,
- val >> 16)) {
- s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
- } else {
- /* Overflow! Stop acquisition!! */
- /* TODO: STOP_ACQUISITION_CALL_HERE!! */
- pcmmio_stop_intr
- (dev,
- s);
- }
-
- /* Check for end of acquisition. */
- if (!subpriv->dio.intr.continuous) {
- /* stop_src == TRIG_COUNT */
- if (subpriv->dio.intr.stop_count > 0) {
- subpriv->dio.intr.stop_count--;
- if (subpriv->dio.intr.stop_count == 0) {
- s->async->events |= COMEDI_CB_EOA;
- /* TODO: STOP_ACQUISITION_CALL_HERE!! */
- pcmmio_stop_intr
- (dev,
- s);
- }
- }
- }
- }
- }
-
- spin_unlock_irqrestore
- (&subpriv->dio.intr.
- spinlock, flags);
-
- if (oldevents !=
- s->async->events) {
- comedi_event(dev, s);
- }
-
- }
-
- }
- }
+ /* are there any interrupts pending */
+ int_pend = inb(dev->iobase + PCMMIO_INT_PENDING_REG) & 0x07;
+ if (!int_pend)
+ return IRQ_NONE;
+
+ /* get, and clear, the pending interrupts */
+ triggered = pcmmio_dio_read(dev, PCMMIO_PAGE_INT_ID, 0);
+ pcmmio_dio_write(dev, 0, PCMMIO_PAGE_INT_ID, 0);
+
+ pcmmio_handle_dio_intr(dev, s, triggered);
- }
- }
- if (!got1)
- return IRQ_NONE; /* interrupt from other source */
return IRQ_HANDLED;
}
+/* devpriv->spinlock is already locked */
static int pcmmio_start_intr(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct pcmmio_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int bits = 0;
+ unsigned int pol_bits = 0;
+ int i;
- if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
+ if (cmd->stop_src == TRIG_COUNT && devpriv->stop_count == 0) {
/* An empty acquisition! */
s->async->events |= COMEDI_CB_EOA;
- subpriv->dio.intr.active = 0;
+ devpriv->active = 0;
return 1;
- } else {
- unsigned bits = 0, pol_bits = 0, n;
- int nports, firstport, asic, port;
- struct comedi_cmd *cmd = &s->async->cmd;
-
- asic = subpriv->dio.intr.asic;
- if (asic < 0)
- return 1; /* not an interrupt
- subdev */
- subpriv->dio.intr.enabled_mask = 0;
- subpriv->dio.intr.active = 1;
- nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
- firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
- if (cmd->chanlist) {
- for (n = 0; n < cmd->chanlist_len; n++) {
- bits |= (1U << CR_CHAN(cmd->chanlist[n]));
- pol_bits |= (CR_AREF(cmd->chanlist[n])
- || CR_RANGE(cmd->
- chanlist[n]) ? 1U : 0U)
- << CR_CHAN(cmd->chanlist[n]);
- }
- }
- bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
- 1) << subpriv->dio.intr.first_chan;
- subpriv->dio.intr.enabled_mask = bits;
-
- {
- /*
- * the below code configures the board
- * to use a specific IRQ from 0-15.
- */
- unsigned char b;
- /*
- * set resource enable register
- * to enable IRQ operation
- */
- outb(1 << 4, dev->iobase + 3);
- /* set bits 0-3 of b to the irq number from 0-15 */
- b = dev->irq & ((1 << 4) - 1);
- outb(b, dev->iobase + 2);
- /* done, we told the board what irq to use */
- }
+ }
- switch_page(dev, asic, PAGE_ENAB);
- for (port = firstport; port < firstport + nports; ++port) {
- unsigned enab =
- bits >> (subpriv->dio.intr.first_chan + (port -
- firstport)
- * 8) & 0xff, pol =
- pol_bits >> (subpriv->dio.intr.first_chan +
- (port - firstport) * 8) & 0xff;
- /* set enab intrs for this subdev.. */
- outb(enab,
- devpriv->asics[asic].iobase + REG_ENAB0 + port);
- switch_page(dev, asic, PAGE_POL);
- outb(pol,
- devpriv->asics[asic].iobase + REG_ENAB0 + port);
+ devpriv->enabled_mask = 0;
+ devpriv->active = 1;
+ if (cmd->chanlist) {
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chanspec = cmd->chanlist[i];
+ unsigned int chan = CR_CHAN(chanspec);
+ unsigned int range = CR_RANGE(chanspec);
+ unsigned int aref = CR_AREF(chanspec);
+
+ bits |= (1 << chan);
+ pol_bits |= (((aref || range) ? 1 : 0) << chan);
}
}
+ bits &= ((1 << s->n_chan) - 1);
+ devpriv->enabled_mask = bits;
+
+ /* set polarity and enable interrupts */
+ pcmmio_dio_write(dev, pol_bits, PCMMIO_PAGE_POL, 0);
+ pcmmio_dio_write(dev, bits, PCMMIO_PAGE_ENAB, 0);
+
return 0;
}
static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ struct pcmmio_private *devpriv = dev->private;
unsigned long flags;
- spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
- if (subpriv->dio.intr.active)
+ spin_lock_irqsave(&devpriv->spinlock, flags);
+ if (devpriv->active)
pcmmio_stop_intr(dev, s);
- spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
+ spin_unlock_irqrestore(&devpriv->spinlock, flags);
return 0;
}
-/*
- * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
- */
-static int
-pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int trignum)
+static int pcmmio_inttrig_start_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int trig_num)
{
+ struct pcmmio_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned long flags;
int event = 0;
- if (trignum != 0)
+ if (trig_num != cmd->start_arg)
return -EINVAL;
- spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
+ spin_lock_irqsave(&devpriv->spinlock, flags);
s->async->inttrig = NULL;
- if (subpriv->dio.intr.active)
+ if (devpriv->active)
event = pcmmio_start_intr(dev, s);
- spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
+ spin_unlock_irqrestore(&devpriv->spinlock, flags);
if (event)
comedi_event(dev, s);
@@ -719,37 +489,27 @@ pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
*/
static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ struct pcmmio_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned long flags;
int event = 0;
- spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
- subpriv->dio.intr.active = 1;
+ spin_lock_irqsave(&devpriv->spinlock, flags);
+ devpriv->active = 1;
/* Set up end of acquisition. */
- switch (cmd->stop_src) {
- case TRIG_COUNT:
- subpriv->dio.intr.continuous = 0;
- subpriv->dio.intr.stop_count = cmd->stop_arg;
- break;
- default:
- /* TRIG_NONE */
- subpriv->dio.intr.continuous = 1;
- subpriv->dio.intr.stop_count = 0;
- break;
- }
+ if (cmd->stop_src == TRIG_COUNT)
+ devpriv->stop_count = cmd->stop_arg;
+ else /* TRIG_NONE */
+ devpriv->stop_count = 0;
/* Set up start of acquisition. */
- switch (cmd->start_src) {
- case TRIG_INT:
+ if (cmd->start_src == TRIG_INT)
s->async->inttrig = pcmmio_inttrig_start_intr;
- break;
- default:
- /* TRIG_NOW */
+ else /* TRIG_NOW */
event = pcmmio_start_intr(dev, s);
- break;
- }
- spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
+
+ spin_unlock_irqrestore(&devpriv->spinlock, flags);
if (event)
comedi_event(dev, s);
@@ -812,188 +572,177 @@ static int pcmmio_cmdtest(struct comedi_device *dev,
return 0;
}
-static int adc_wait_ready(unsigned long iobase)
+static int pcmmio_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- unsigned long retry = 100000;
- while (retry--)
- if (inb(iobase + 3) & 0x80)
- return 0;
- return 1;
+ unsigned char status;
+
+ status = inb(dev->iobase + PCMMIO_AI_STATUS_REG);
+ if (status & PCMMIO_AI_STATUS_DATA_READY)
+ return 0;
+ return -EBUSY;
}
-/* All this is for AI and AO */
-static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int pcmmio_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int n;
- unsigned long iobase = subpriv->iobase;
+ unsigned long iobase = dev->iobase;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int aref = CR_AREF(insn->chanspec);
+ unsigned char cmd = 0;
+ unsigned int val;
+ int ret;
+ int i;
/*
- 1. write the CMD byte (to BASE+2)
- 2. read junk lo byte (BASE+0)
- 3. read junk hi byte (BASE+1)
- 4. (mux settled so) write CMD byte again (BASE+2)
- 5. read valid lo byte(BASE+0)
- 6. read valid hi byte(BASE+1)
-
- Additionally note that the BASE += 4 if the channel >= 8
+ * The PCM-MIO uses two Linear Tech LTC1859CG 8-channel A/D converters.
+ * The devices use a full duplex serial interface which transmits and
+ * receives data simultaneously. An 8-bit command is shifted into the
+ * ADC interface to configure it for the next conversion. At the same
+ * time, the data from the previous conversion is shifted out of the
+ * device. Consequently, the conversion result is delayed by one
+ * conversion from the command word.
+ *
+ * Setup the cmd for the conversions then do a dummy conversion to
+ * flush the junk data. Then do each conversion requested by the
+ * comedi_insn. Note that the last conversion will leave junk data
+ * in ADC which will get flushed on the next comedi_insn.
*/
- /* convert n samples */
- for (n = 0; n < insn->n; n++) {
- unsigned chan = CR_CHAN(insn->chanspec), range =
- CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
- unsigned char command_byte = 0;
- unsigned iooffset = 0;
- unsigned short sample, adc_adjust = 0;
-
- if (chan > 7)
- chan -= 8, iooffset = 4; /*
- * use the second dword
- * for channels > 7
- */
-
- if (aref != AREF_DIFF) {
- aref = AREF_GROUND;
- command_byte |= 1 << 7; /*
- * set bit 7 to indicate
- * single-ended
- */
- }
- if (range < 2)
- adc_adjust = 0x8000; /*
- * bipolar ranges
- * (-5,5 .. -10,10 need to be
- * adjusted -- that is.. they
- * need to wrap around by
- * adding 0x8000
- */
-
- if (chan % 2) {
- command_byte |= 1 << 6; /*
- * odd-numbered channels
- * have bit 6 set
- */
- }
+ if (chan > 7) {
+ chan -= 8;
+ iobase += PCMMIO_AI_2ND_ADC_OFFSET;
+ }
+
+ if (aref == AREF_GROUND)
+ cmd |= PCMMIO_AI_CMD_SE;
+ if (chan % 2)
+ cmd |= PCMMIO_AI_CMD_ODD_CHAN;
+ cmd |= PCMMIO_AI_CMD_CHAN_SEL(chan / 2);
+ cmd |= PCMMIO_AI_CMD_RANGE(range);
- /* select the channel, bits 4-5 == chan/2 */
- command_byte |= ((chan / 2) & 0x3) << 4;
+ outb(cmd, iobase + PCMMIO_AI_CMD_REG);
- /* set the range, bits 2-3 */
- command_byte |= (range & 0x3) << 2;
+ ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0);
+ if (ret)
+ return ret;
- /* need to do this twice to make sure mux settled */
- /* chan/range/aref select */
- outb(command_byte, iobase + iooffset + 2);
+ val = inb(iobase + PCMMIO_AI_LSB_REG);
+ val |= inb(iobase + PCMMIO_AI_MSB_REG) << 8;
- /* wait for the adc to say it finised the conversion */
- adc_wait_ready(iobase + iooffset);
+ for (i = 0; i < insn->n; i++) {
+ outb(cmd, iobase + PCMMIO_AI_CMD_REG);
- /* select the chan/range/aref AGAIN */
- outb(command_byte, iobase + iooffset + 2);
+ ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0);
+ if (ret)
+ return ret;
- adc_wait_ready(iobase + iooffset);
+ val = inb(iobase + PCMMIO_AI_LSB_REG);
+ val |= inb(iobase + PCMMIO_AI_MSB_REG) << 8;
- /* read data lo byte */
- sample = inb(iobase + iooffset + 0);
+ /* bipolar data is two's complement */
+ if (comedi_range_is_bipolar(s, range))
+ val = comedi_offset_munge(s, val);
- /* read data hi byte */
- sample |= inb(iobase + iooffset + 1) << 8;
- sample += adc_adjust; /* adjustment .. munge data */
- data[n] = sample;
+ data[i] = val;
}
- /* return the number of samples read/written */
- return n;
+
+ return insn->n;
}
-static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int pcmmio_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int n;
- for (n = 0; n < insn->n; n++) {
- unsigned chan = CR_CHAN(insn->chanspec);
- if (chan < s->n_chan)
- data[n] = subpriv->ao.shadow_samples[chan];
- }
- return n;
+ struct pcmmio_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
+
+ return insn->n;
}
-static int wait_dac_ready(unsigned long iobase)
+static int pcmmio_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- unsigned long retry = 100000L;
+ unsigned char status;
- /* This may seem like an absurd way to handle waiting and violates the
- "no busy waiting" policy. The fact is that the hardware is
- normally so fast that we usually only need one time through the loop
- anyway. The longer timeout is for rare occasions and for detecting
- non-existent hardware. */
+ status = inb(dev->iobase + PCMMIO_AO_STATUS_REG);
+ if (status & PCMMIO_AO_STATUS_DATA_READY)
+ return 0;
+ return -EBUSY;
+}
+
+static int pcmmio_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct pcmmio_private *devpriv = dev->private;
+ unsigned long iobase = dev->iobase;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int val = devpriv->ao_readback[chan];
+ unsigned char cmd = 0;
+ int ret;
+ int i;
- while (retry--) {
- if (inb(iobase + 3) & 0x80)
- return 0;
+ /*
+ * The PCM-MIO has two Linear Tech LTC2704 DAC devices. Each device
+ * is a 4-channel converter with software-selectable output range.
+ */
+ if (chan > 3) {
+ cmd |= PCMMIO_AO_CMD_CHAN_SEL(chan - 4);
+ iobase += PCMMIO_AO_2ND_DAC_OFFSET;
+ } else {
+ cmd |= PCMMIO_AO_CMD_CHAN_SEL(chan);
}
- return 1;
-}
-static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int n;
- unsigned iobase = subpriv->iobase, iooffset = 0;
-
- for (n = 0; n < insn->n; n++) {
- unsigned chan = CR_CHAN(insn->chanspec), range =
- CR_RANGE(insn->chanspec);
- if (chan < s->n_chan) {
- unsigned char command_byte = 0, range_byte =
- range & ((1 << 4) - 1);
- if (chan >= 4)
- chan -= 4, iooffset += 4;
- /* set the range.. */
- outb(range_byte, iobase + iooffset + 0);
- outb(0, iobase + iooffset + 1);
-
- /* tell it to begin */
- command_byte = (chan << 1) | 0x60;
- outb(command_byte, iobase + iooffset + 2);
-
- wait_dac_ready(iobase + iooffset);
-
- /* low order byte */
- outb(data[n] & 0xff, iobase + iooffset + 0);
-
- /* high order byte */
- outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);
-
- /*
- * set bit 4 of command byte to indicate
- * data is loaded and trigger conversion
- */
- command_byte = 0x70 | (chan << 1);
- /* trigger converion */
- outb(command_byte, iobase + iooffset + 2);
-
- wait_dac_ready(iobase + iooffset);
-
- /* save to shadow register for ao_rinsn */
- subpriv->ao.shadow_samples[chan] = data[n];
- }
+ /* set the range for the channel */
+ outb(PCMMIO_AO_LSB_SPAN(range), iobase + PCMMIO_AO_LSB_REG);
+ outb(0, iobase + PCMMIO_AO_MSB_REG);
+ outb(cmd | PCMMIO_AO_CMD_WR_SPAN_UPDATE, iobase + PCMMIO_AO_CMD_REG);
+
+ ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+
+ /* write the data to the channel */
+ outb(val & 0xff, iobase + PCMMIO_AO_LSB_REG);
+ outb((val >> 8) & 0xff, iobase + PCMMIO_AO_MSB_REG);
+ outb(cmd | PCMMIO_AO_CMD_WR_CODE_UPDATE,
+ iobase + PCMMIO_AO_CMD_REG);
+
+ ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0);
+ if (ret)
+ return ret;
+
+ devpriv->ao_readback[chan] = val;
}
- return n;
+
+ return insn->n;
}
static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct pcmmio_private *devpriv;
struct comedi_subdevice *s;
- int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
- thisasic_chanct = 0;
- unsigned int irq[MAX_ASICS];
int ret;
- irq[0] = it->options[1];
-
ret = comedi_request_region(dev, it->options[0], 32);
if (ret)
return ret;
@@ -1002,177 +751,99 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (!devpriv)
return -ENOMEM;
- for (asic = 0; asic < MAX_ASICS; ++asic) {
- devpriv->asics[asic].num = asic;
- devpriv->asics[asic].iobase =
- dev->iobase + 16 + asic * ASIC_IOSIZE;
- /*
- * this gets actually set at the end of this function when we
- * request_irqs
- */
- devpriv->asics[asic].irq = 0;
- spin_lock_init(&devpriv->asics[asic].spinlock);
- }
+ spin_lock_init(&devpriv->pagelock);
+ spin_lock_init(&devpriv->spinlock);
- chans_left = CHANS_PER_ASIC * 1;
- n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
- n_subdevs = n_dio_subdevs + 2;
- devpriv->sprivs =
- kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
- GFP_KERNEL);
- if (!devpriv->sprivs) {
- printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
- dev->minor);
- return -ENOMEM;
+ pcmmio_reset(dev);
+
+ if (it->options[1]) {
+ ret = request_irq(it->options[1], interrupt_pcmmio, 0,
+ dev->board_name, dev);
+ if (ret == 0) {
+ dev->irq = it->options[1];
+
+ /* configure the interrupt routing on the board */
+ outb(PCMMIO_AI_RES_ENA_DIO_RES_ACCESS,
+ dev->iobase + PCMMIO_AI_RES_ENA_REG);
+ outb(PCMMIO_RESOURCE_IRQ(dev->irq),
+ dev->iobase + PCMMIO_RESOURCE_REG);
+ }
}
- ret = comedi_alloc_subdevices(dev, n_subdevs);
+ ret = comedi_alloc_subdevices(dev, 4);
if (ret)
return ret;
- /* First, AI */
+ /* Analog Input subdevice */
s = &dev->subdevices[0];
- s->private = &devpriv->sprivs[0];
- s->maxdata = 0xffff;
- s->range_table = &ranges_ai;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
- s->type = COMEDI_SUBD_AI;
- s->n_chan = 16;
- s->len_chanlist = s->n_chan;
- s->insn_read = ai_rinsn;
- subpriv->iobase = dev->iobase + 0;
- /* initialize the resource enable register by clearing it */
- outb(0, subpriv->iobase + 3);
- outb(0, subpriv->iobase + 4 + 3);
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
+ s->n_chan = 16;
+ s->maxdata = 0xffff;
+ s->range_table = &pcmmio_ai_ranges;
+ s->insn_read = pcmmio_ai_insn_read;
- /* Next, AO */
- s = &dev->subdevices[1];
- s->private = &devpriv->sprivs[1];
- s->maxdata = 0xffff;
- s->range_table = &ranges_ao;
- s->subdev_flags = SDF_READABLE;
- s->type = COMEDI_SUBD_AO;
- s->n_chan = 8;
- s->len_chanlist = s->n_chan;
- s->insn_read = ao_rinsn;
- s->insn_write = ao_winsn;
- subpriv->iobase = dev->iobase + 8;
/* initialize the resource enable register by clearing it */
- outb(0, subpriv->iobase + 3);
- outb(0, subpriv->iobase + 4 + 3);
-
- port = 0;
- asic = 0;
- for (sdev_no = 2; sdev_no < dev->n_subdevices; ++sdev_no) {
- int byte_no;
-
- s = &dev->subdevices[sdev_no];
- s->private = &devpriv->sprivs[sdev_no];
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->type = COMEDI_SUBD_DIO;
- s->insn_bits = pcmmio_dio_insn_bits;
- s->insn_config = pcmmio_dio_insn_config;
- s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
- subpriv->dio.intr.asic = -1;
- subpriv->dio.intr.first_chan = -1;
- subpriv->dio.intr.asic_chan = -1;
- subpriv->dio.intr.num_asic_chans = -1;
- subpriv->dio.intr.active = 0;
- s->len_chanlist = 1;
-
- /* save the ioport address for each 'port' of 8 channels in the
- subdevice */
- for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
- if (port >= PORTS_PER_ASIC) {
- port = 0;
- ++asic;
- thisasic_chanct = 0;
- }
- subpriv->iobases[byte_no] =
- devpriv->asics[asic].iobase + port;
-
- if (thisasic_chanct <
- CHANS_PER_PORT * INTR_PORTS_PER_ASIC
- && subpriv->dio.intr.asic < 0) {
- /*
- * this is an interrupt subdevice,
- * so setup the struct
- */
- subpriv->dio.intr.asic = asic;
- subpriv->dio.intr.active = 0;
- subpriv->dio.intr.stop_count = 0;
- subpriv->dio.intr.first_chan = byte_no * 8;
- subpriv->dio.intr.asic_chan = thisasic_chanct;
- subpriv->dio.intr.num_asic_chans =
- s->n_chan - subpriv->dio.intr.first_chan;
- s->cancel = pcmmio_cancel;
- s->do_cmd = pcmmio_cmd;
- s->do_cmdtest = pcmmio_cmdtest;
- s->len_chanlist =
- subpriv->dio.intr.num_asic_chans;
- }
- thisasic_chanct += CHANS_PER_PORT;
- }
- spin_lock_init(&subpriv->dio.intr.spinlock);
-
- chans_left -= s->n_chan;
+ outb(PCMMIO_AI_RES_ENA_CMD_REG_ACCESS,
+ dev->iobase + PCMMIO_AI_RES_ENA_REG);
+ outb(PCMMIO_AI_RES_ENA_CMD_REG_ACCESS,
+ dev->iobase + PCMMIO_AI_RES_ENA_REG + PCMMIO_AI_2ND_ADC_OFFSET);
- if (!chans_left) {
- /*
- * reset the asic to our first asic,
- * to do intr subdevs
- */
- asic = 0;
- port = 0;
- }
-
- }
+ /* Analog Output subdevice */
+ s = &dev->subdevices[1];
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 8;
+ s->maxdata = 0xffff;
+ s->range_table = &pcmmio_ao_ranges;
+ s->insn_read = pcmmio_ao_insn_read;
+ s->insn_write = pcmmio_ao_insn_write;
- init_asics(dev); /* clear out all the registers, basically */
-
- for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
- if (irq[asic]
- && request_irq(irq[asic], interrupt_pcmmio,
- IRQF_SHARED, dev->board_name, dev)) {
- int i;
- /* unroll the allocated irqs.. */
- for (i = asic - 1; i >= 0; --i) {
- free_irq(irq[i], dev);
- devpriv->asics[i].irq = irq[i] = 0;
- }
- irq[asic] = 0;
- }
- devpriv->asics[asic].irq = irq[asic];
+ /* initialize the resource enable register by clearing it */
+ outb(0, dev->iobase + PCMMIO_AO_RESOURCE_ENA_REG);
+ outb(0, dev->iobase + PCMMIO_AO_2ND_DAC_OFFSET +
+ PCMMIO_AO_RESOURCE_ENA_REG);
+
+ /* Digital I/O subdevice with interrupt support */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 24;
+ s->maxdata = 1;
+ s->len_chanlist = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcmmio_dio_insn_bits;
+ s->insn_config = pcmmio_dio_insn_config;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = s->n_chan;
+ s->cancel = pcmmio_cancel;
+ s->do_cmd = pcmmio_cmd;
+ s->do_cmdtest = pcmmio_cmdtest;
}
- return 1;
-}
-
-static void pcmmio_detach(struct comedi_device *dev)
-{
- struct pcmmio_private *devpriv = dev->private;
- int i;
+ /* Digital I/O subdevice */
+ s = &dev->subdevices[3];
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 24;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcmmio_dio_insn_bits;
+ s->insn_config = pcmmio_dio_insn_config;
- if (devpriv) {
- for (i = 0; i < MAX_ASICS; ++i) {
- if (devpriv->asics[i].irq)
- free_irq(devpriv->asics[i].irq, dev);
- }
- kfree(devpriv->sprivs);
- }
- comedi_legacy_detach(dev);
+ return 0;
}
static struct comedi_driver pcmmio_driver = {
.driver_name = "pcmmio",
.module = THIS_MODULE,
.attach = pcmmio_attach,
- .detach = pcmmio_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(pcmmio_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for Winsystems PCM-MIO PC/104 board");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index 954fa96a50a..62914bb342d 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -75,7 +75,6 @@
#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/slab.h>
#include "../comedidev.h"
@@ -127,36 +126,53 @@ static const struct pcmuio_board pcmuio_boards[] = {
},
};
-struct pcmuio_subdev_private {
- /* The below is only used for intr subdevices */
- struct {
- /* if non-negative, this subdev has an interrupt asic */
- int asic;
- /*
- * subdev-relative channel mask for channels
- * we are interested in
- */
- int enabled_mask;
- int active;
- int stop_count;
- int continuous;
- spinlock_t spinlock;
- } intr;
+struct pcmuio_asic {
+ spinlock_t pagelock; /* protects the page registers */
+ spinlock_t spinlock; /* protects member variables */
+ unsigned int enabled_mask;
+ unsigned int stop_count;
+ unsigned int active:1;
+ unsigned int continuous:1;
};
struct pcmuio_private {
- struct {
- unsigned int irq;
- spinlock_t spinlock;
- } asics[PCMUIO_MAX_ASICS];
- struct pcmuio_subdev_private *sprivs;
+ struct pcmuio_asic asics[PCMUIO_MAX_ASICS];
+ unsigned int irq2;
};
+static inline unsigned long pcmuio_asic_iobase(struct comedi_device *dev,
+ int asic)
+{
+ return dev->iobase + (asic * PCMUIO_ASIC_IOSIZE);
+}
+
+static inline int pcmuio_subdevice_to_asic(struct comedi_subdevice *s)
+{
+ /*
+ * subdevice 0 and 1 are handled by the first asic
+ * subdevice 2 and 3 are handled by the second asic
+ */
+ return s->index / 2;
+}
+
+static inline int pcmuio_subdevice_to_port(struct comedi_subdevice *s)
+{
+ /*
+ * subdevice 0 and 2 use port registers 0-2
+ * subdevice 1 and 3 use port registers 3-5
+ */
+ return (s->index % 2) ? 3 : 0;
+}
+
static void pcmuio_write(struct comedi_device *dev, unsigned int val,
int asic, int page, int port)
{
- unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE);
+ struct pcmuio_private *devpriv = dev->private;
+ struct pcmuio_asic *chip = &devpriv->asics[asic];
+ unsigned long iobase = pcmuio_asic_iobase(dev, asic);
+ unsigned long flags;
+ spin_lock_irqsave(&chip->pagelock, flags);
if (page == 0) {
/* Port registers are valid for any page */
outb(val & 0xff, iobase + PCMUIO_PORT_REG(port + 0));
@@ -168,14 +184,19 @@ static void pcmuio_write(struct comedi_device *dev, unsigned int val,
outb((val >> 8) & 0xff, iobase + PCMUIO_PAGE_REG(1));
outb((val >> 16) & 0xff, iobase + PCMUIO_PAGE_REG(2));
}
+ spin_unlock_irqrestore(&chip->pagelock, flags);
}
static unsigned int pcmuio_read(struct comedi_device *dev,
int asic, int page, int port)
{
- unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE);
+ struct pcmuio_private *devpriv = dev->private;
+ struct pcmuio_asic *chip = &devpriv->asics[asic];
+ unsigned long iobase = pcmuio_asic_iobase(dev, asic);
+ unsigned long flags;
unsigned int val;
+ spin_lock_irqsave(&chip->pagelock, flags);
if (page == 0) {
/* Port registers are valid for any page */
val = inb(iobase + PCMUIO_PORT_REG(port + 0));
@@ -187,6 +208,7 @@ static unsigned int pcmuio_read(struct comedi_device *dev,
val |= (inb(iobase + PCMUIO_PAGE_REG(1)) << 8);
val |= (inb(iobase + PCMUIO_PAGE_REG(2)) << 16);
}
+ spin_unlock_irqrestore(&chip->pagelock, flags);
return val;
}
@@ -203,30 +225,35 @@ static unsigned int pcmuio_read(struct comedi_device *dev,
*/
static int pcmuio_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- unsigned int mask = data[0] & s->io_bits; /* outputs only */
- unsigned int bits = data[1];
- int asic = s->index / 2;
- int port = (s->index % 2) ? 3 : 0;
+ int asic = pcmuio_subdevice_to_asic(s);
+ int port = pcmuio_subdevice_to_port(s);
+ unsigned int chanmask = (1 << s->n_chan) - 1;
+ unsigned int mask;
unsigned int val;
- /* get inverted state of the channels from the port */
- val = pcmuio_read(dev, asic, 0, port);
-
- /* get the true state of the channels */
- s->state = val ^ ((0x1 << s->n_chan) - 1);
-
+ mask = comedi_dio_update_state(s, data);
if (mask) {
- s->state &= ~mask;
- s->state |= (mask & bits);
-
- /* invert the state and update the channels */
- val = s->state ^ ((0x1 << s->n_chan) - 1);
+ /*
+ * Outputs are inverted, invert the state and
+ * update the channels.
+ *
+ * The s->io_bits mask makes sure the input channels
+ * are '0' so that the outputs pins stay in a high
+ * z-state.
+ */
+ val = ~s->state & chanmask;
+ val &= s->io_bits;
pcmuio_write(dev, val, asic, 0, port);
}
- data[1] = s->state;
+ /* get inverted state of the channels from the port */
+ val = pcmuio_read(dev, asic, 0, port);
+
+ /* return the true state of the channels */
+ data[1] = ~val & chanmask;
return insn->n;
}
@@ -236,8 +263,8 @@ static int pcmuio_dio_insn_config(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- int asic = s->index / 2;
- int port = (s->index % 2) ? 3 : 0;
+ int asic = pcmuio_subdevice_to_asic(s);
+ int port = pcmuio_subdevice_to_port(s);
int ret;
ret = comedi_dio_insn_config(dev, s, insn, data, 0);
@@ -267,18 +294,16 @@ static void pcmuio_reset(struct comedi_device *dev)
}
}
+/* chip->spinlock is already locked */
static void pcmuio_stop_intr(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- struct pcmuio_subdev_private *subpriv = s->private;
- int asic;
-
- asic = subpriv->intr.asic;
- if (asic < 0)
- return; /* not an interrupt subdev */
+ struct pcmuio_private *devpriv = dev->private;
+ int asic = pcmuio_subdevice_to_asic(s);
+ struct pcmuio_asic *chip = &devpriv->asics[asic];
- subpriv->intr.enabled_mask = 0;
- subpriv->intr.active = 0;
+ chip->enabled_mask = 0;
+ chip->active = 0;
s->async->inttrig = NULL;
/* disable all intrs for this subdev.. */
@@ -289,34 +314,32 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned triggered)
{
- struct pcmuio_subdev_private *subpriv = s->private;
- unsigned int len = s->async->cmd.chanlist_len;
+ struct pcmuio_private *devpriv = dev->private;
+ int asic = pcmuio_subdevice_to_asic(s);
+ struct pcmuio_asic *chip = &devpriv->asics[asic];
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned oldevents = s->async->events;
unsigned int val = 0;
unsigned long flags;
- unsigned mytrig;
unsigned int i;
- spin_lock_irqsave(&subpriv->intr.spinlock, flags);
+ spin_lock_irqsave(&chip->spinlock, flags);
- if (!subpriv->intr.active)
+ if (!chip->active)
goto done;
- mytrig = triggered;
- mytrig &= ((0x1 << s->n_chan) - 1);
-
- if (!(mytrig & subpriv->intr.enabled_mask))
+ if (!(triggered & chip->enabled_mask))
goto done;
- for (i = 0; i < len; i++) {
- unsigned int chan = CR_CHAN(s->async->cmd.chanlist[i]);
- if (mytrig & (1U << chan))
- val |= (1U << i);
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+ if (triggered & (1 << chan))
+ val |= (1 << i);
}
/* Write the scan to the buffer. */
- if (comedi_buf_put(s->async, val) &&
- comedi_buf_put(s->async, val >> 16)) {
+ if (comedi_buf_put(s, val) &&
+ comedi_buf_put(s, val >> 16)) {
s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
} else {
/* Overflow! Stop acquisition!! */
@@ -325,11 +348,11 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev,
}
/* Check for end of acquisition. */
- if (!subpriv->intr.continuous) {
+ if (!chip->continuous) {
/* stop_src == TRIG_COUNT */
- if (subpriv->intr.stop_count > 0) {
- subpriv->intr.stop_count--;
- if (subpriv->intr.stop_count == 0) {
+ if (chip->stop_count > 0) {
+ chip->stop_count--;
+ if (chip->stop_count == 0) {
s->async->events |= COMEDI_CB_EOA;
/* TODO: STOP_ACQUISITION_CALL_HERE!! */
pcmuio_stop_intr(dev, s);
@@ -338,7 +361,7 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev,
}
done:
- spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
+ spin_unlock_irqrestore(&chip->spinlock, flags);
if (oldevents != s->async->events)
comedi_event(dev, s);
@@ -346,138 +369,117 @@ done:
static int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic)
{
- struct pcmuio_private *devpriv = dev->private;
- struct pcmuio_subdev_private *subpriv;
- unsigned long iobase = dev->iobase + (asic * PCMUIO_ASIC_IOSIZE);
- unsigned int triggered = 0;
- int got1 = 0;
- unsigned long flags;
- unsigned char int_pend;
- int i;
+ /* there are could be two asics so we can't use dev->read_subdev */
+ struct comedi_subdevice *s = &dev->subdevices[asic * 2];
+ unsigned long iobase = pcmuio_asic_iobase(dev, asic);
+ unsigned int val;
- spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags);
+ /* are there any interrupts pending */
+ val = inb(iobase + PCMUIO_INT_PENDING_REG) & 0x07;
+ if (!val)
+ return 0;
- int_pend = inb(iobase + PCMUIO_INT_PENDING_REG) & 0x07;
- if (int_pend) {
- triggered = pcmuio_read(dev, asic, PCMUIO_PAGE_INT_ID, 0);
- pcmuio_write(dev, 0, asic, PCMUIO_PAGE_INT_ID, 0);
+ /* get, and clear, the pending interrupts */
+ val = pcmuio_read(dev, asic, PCMUIO_PAGE_INT_ID, 0);
+ pcmuio_write(dev, 0, asic, PCMUIO_PAGE_INT_ID, 0);
- ++got1;
- }
+ /* handle the pending interrupts */
+ pcmuio_handle_intr_subdev(dev, s, val);
- spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags);
-
- if (triggered) {
- struct comedi_subdevice *s;
- /* TODO here: dispatch io lines to subdevs with commands.. */
- for (i = 0; i < dev->n_subdevices; i++) {
- s = &dev->subdevices[i];
- subpriv = s->private;
- if (subpriv->intr.asic == asic) {
- /*
- * This is an interrupt subdev, and it
- * matches this asic!
- */
- pcmuio_handle_intr_subdev(dev, s,
- triggered);
- }
- }
- }
- return got1;
+ return 1;
}
static irqreturn_t pcmuio_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
struct pcmuio_private *devpriv = dev->private;
- int got1 = 0;
- int asic;
+ int handled = 0;
- for (asic = 0; asic < PCMUIO_MAX_ASICS; ++asic) {
- if (irq == devpriv->asics[asic].irq) {
- /* it is an interrupt for ASIC #asic */
- if (pcmuio_handle_asic_interrupt(dev, asic))
- got1++;
- }
- }
- if (!got1)
- return IRQ_NONE; /* interrupt from other source */
- return IRQ_HANDLED;
+ if (irq == dev->irq)
+ handled += pcmuio_handle_asic_interrupt(dev, 0);
+ if (irq == devpriv->irq2)
+ handled += pcmuio_handle_asic_interrupt(dev, 1);
+
+ return handled ? IRQ_HANDLED : IRQ_NONE;
}
+/* chip->spinlock is already locked */
static int pcmuio_start_intr(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- struct pcmuio_subdev_private *subpriv = s->private;
+ struct pcmuio_private *devpriv = dev->private;
+ int asic = pcmuio_subdevice_to_asic(s);
+ struct pcmuio_asic *chip = &devpriv->asics[asic];
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int bits = 0;
+ unsigned int pol_bits = 0;
+ int i;
- if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) {
+ if (!chip->continuous && chip->stop_count == 0) {
/* An empty acquisition! */
s->async->events |= COMEDI_CB_EOA;
- subpriv->intr.active = 0;
+ chip->active = 0;
return 1;
- } else {
- unsigned bits = 0, pol_bits = 0, n;
- int asic;
- struct comedi_cmd *cmd = &s->async->cmd;
-
- asic = subpriv->intr.asic;
- if (asic < 0)
- return 1; /* not an interrupt
- subdev */
- subpriv->intr.enabled_mask = 0;
- subpriv->intr.active = 1;
- if (cmd->chanlist) {
- for (n = 0; n < cmd->chanlist_len; n++) {
- bits |= (1U << CR_CHAN(cmd->chanlist[n]));
- pol_bits |= (CR_AREF(cmd->chanlist[n])
- || CR_RANGE(cmd->
- chanlist[n]) ? 1U : 0U)
- << CR_CHAN(cmd->chanlist[n]);
- }
- }
- bits &= ((0x1 << s->n_chan) - 1);
- subpriv->intr.enabled_mask = bits;
+ }
- /* set pol and enab intrs for this subdev.. */
- pcmuio_write(dev, pol_bits, asic, PCMUIO_PAGE_POL, 0);
- pcmuio_write(dev, bits, asic, PCMUIO_PAGE_ENAB, 0);
+ chip->enabled_mask = 0;
+ chip->active = 1;
+ if (cmd->chanlist) {
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chanspec = cmd->chanlist[i];
+ unsigned int chan = CR_CHAN(chanspec);
+ unsigned int range = CR_RANGE(chanspec);
+ unsigned int aref = CR_AREF(chanspec);
+
+ bits |= (1 << chan);
+ pol_bits |= ((aref || range) ? 1 : 0) << chan;
+ }
}
+ bits &= ((1 << s->n_chan) - 1);
+ chip->enabled_mask = bits;
+
+ /* set pol and enab intrs for this subdev.. */
+ pcmuio_write(dev, pol_bits, asic, PCMUIO_PAGE_POL, 0);
+ pcmuio_write(dev, bits, asic, PCMUIO_PAGE_ENAB, 0);
+
return 0;
}
static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
- struct pcmuio_subdev_private *subpriv = s->private;
+ struct pcmuio_private *devpriv = dev->private;
+ int asic = pcmuio_subdevice_to_asic(s);
+ struct pcmuio_asic *chip = &devpriv->asics[asic];
unsigned long flags;
- spin_lock_irqsave(&subpriv->intr.spinlock, flags);
- if (subpriv->intr.active)
+ spin_lock_irqsave(&chip->spinlock, flags);
+ if (chip->active)
pcmuio_stop_intr(dev, s);
- spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
+ spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
-/*
- * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
- */
-static int
-pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int trignum)
+static int pcmuio_inttrig_start_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int trig_num)
{
- struct pcmuio_subdev_private *subpriv = s->private;
+ struct pcmuio_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ int asic = pcmuio_subdevice_to_asic(s);
+ struct pcmuio_asic *chip = &devpriv->asics[asic];
unsigned long flags;
int event = 0;
- if (trignum != 0)
+ if (trig_num != cmd->start_arg)
return -EINVAL;
- spin_lock_irqsave(&subpriv->intr.spinlock, flags);
+ spin_lock_irqsave(&chip->spinlock, flags);
s->async->inttrig = NULL;
- if (subpriv->intr.active)
+ if (chip->active)
event = pcmuio_start_intr(dev, s);
- spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
+ spin_unlock_irqrestore(&chip->spinlock, flags);
if (event)
comedi_event(dev, s);
@@ -490,38 +492,36 @@ pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
*/
static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
- struct pcmuio_subdev_private *subpriv = s->private;
+ struct pcmuio_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
+ int asic = pcmuio_subdevice_to_asic(s);
+ struct pcmuio_asic *chip = &devpriv->asics[asic];
unsigned long flags;
int event = 0;
- spin_lock_irqsave(&subpriv->intr.spinlock, flags);
- subpriv->intr.active = 1;
+ spin_lock_irqsave(&chip->spinlock, flags);
+ chip->active = 1;
/* Set up end of acquisition. */
switch (cmd->stop_src) {
case TRIG_COUNT:
- subpriv->intr.continuous = 0;
- subpriv->intr.stop_count = cmd->stop_arg;
+ chip->continuous = 0;
+ chip->stop_count = cmd->stop_arg;
break;
default:
/* TRIG_NONE */
- subpriv->intr.continuous = 1;
- subpriv->intr.stop_count = 0;
+ chip->continuous = 1;
+ chip->stop_count = 0;
break;
}
/* Set up start of acquisition. */
- switch (cmd->start_src) {
- case TRIG_INT:
+ if (cmd->start_src == TRIG_INT)
s->async->inttrig = pcmuio_inttrig_start_intr;
- break;
- default:
- /* TRIG_NOW */
+ else /* TRIG_NOW */
event = pcmuio_start_intr(dev, s);
- break;
- }
- spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
+
+ spin_unlock_irqrestore(&chip->spinlock, flags);
if (event)
comedi_event(dev, s);
@@ -589,13 +589,8 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
const struct pcmuio_board *board = comedi_board(dev);
struct comedi_subdevice *s;
struct pcmuio_private *devpriv;
- struct pcmuio_subdev_private *subpriv;
- int sdev_no, n_subdevs, asic;
- unsigned int irq[PCMUIO_MAX_ASICS];
int ret;
-
- irq[0] = it->options[1];
- irq[1] = it->options[2];
+ int i;
ret = comedi_request_region(dev, it->options[0],
board->num_asics * PCMUIO_ASIC_IOSIZE);
@@ -606,62 +601,60 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (!devpriv)
return -ENOMEM;
- for (asic = 0; asic < PCMUIO_MAX_ASICS; ++asic)
- spin_lock_init(&devpriv->asics[asic].spinlock);
+ for (i = 0; i < PCMUIO_MAX_ASICS; ++i) {
+ struct pcmuio_asic *chip = &devpriv->asics[i];
- n_subdevs = board->num_asics * 2;
- devpriv->sprivs = kcalloc(n_subdevs, sizeof(*subpriv), GFP_KERNEL);
- if (!devpriv->sprivs)
- return -ENOMEM;
+ spin_lock_init(&chip->pagelock);
+ spin_lock_init(&chip->spinlock);
+ }
- ret = comedi_alloc_subdevices(dev, n_subdevs);
- if (ret)
- return ret;
+ pcmuio_reset(dev);
- for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
- s = &dev->subdevices[sdev_no];
- subpriv = &devpriv->sprivs[sdev_no];
- s->private = subpriv;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->type = COMEDI_SUBD_DIO;
- s->insn_bits = pcmuio_dio_insn_bits;
- s->insn_config = pcmuio_dio_insn_config;
- s->n_chan = 24;
-
- /* subdevices 0 and 2 suppport interrupts */
- if ((sdev_no % 2) == 0) {
- /* setup the interrupt subdevice */
- subpriv->intr.asic = sdev_no / 2;
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->cancel = pcmuio_cancel;
- s->do_cmd = pcmuio_cmd;
- s->do_cmdtest = pcmuio_cmdtest;
- s->len_chanlist = s->n_chan;
- } else {
- subpriv->intr.asic = -1;
- s->len_chanlist = 1;
+ if (it->options[1]) {
+ /* request the irq for the 1st asic */
+ ret = request_irq(it->options[1], pcmuio_interrupt, 0,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = it->options[1];
+ }
+
+ if (board->num_asics == 2) {
+ if (it->options[2] == dev->irq) {
+ /* the same irq (or none) is used by both asics */
+ devpriv->irq2 = it->options[2];
+ } else if (it->options[2]) {
+ /* request the irq for the 2nd asic */
+ ret = request_irq(it->options[2], pcmuio_interrupt, 0,
+ dev->board_name, dev);
+ if (ret == 0)
+ devpriv->irq2 = it->options[2];
}
- spin_lock_init(&subpriv->intr.spinlock);
}
- pcmuio_reset(dev);
+ ret = comedi_alloc_subdevices(dev, board->num_asics * 2);
+ if (ret)
+ return ret;
- for (asic = 0; irq[0] && asic < PCMUIO_MAX_ASICS; ++asic) {
- if (irq[asic]
- && request_irq(irq[asic], pcmuio_interrupt,
- IRQF_SHARED, board->name, dev)) {
- int i;
- /* unroll the allocated irqs.. */
- for (i = asic - 1; i >= 0; --i) {
- free_irq(irq[i], dev);
- devpriv->asics[i].irq = irq[i] = 0;
- }
- irq[asic] = 0;
+ for (i = 0; i < dev->n_subdevices; ++i) {
+ s = &dev->subdevices[i];
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 24;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pcmuio_dio_insn_bits;
+ s->insn_config = pcmuio_dio_insn_config;
+
+ /* subdevices 0 and 2 can suppport interrupts */
+ if ((i == 0 && dev->irq) || (i == 2 && devpriv->irq2)) {
+ /* setup the interrupt subdevice */
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = s->n_chan;
+ s->cancel = pcmuio_cancel;
+ s->do_cmd = pcmuio_cmd;
+ s->do_cmdtest = pcmuio_cmdtest;
}
- devpriv->asics[asic].irq = irq[asic];
}
return 0;
@@ -670,14 +663,13 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
static void pcmuio_detach(struct comedi_device *dev)
{
struct pcmuio_private *devpriv = dev->private;
- int i;
if (devpriv) {
- for (i = 0; i < PCMUIO_MAX_ASICS; ++i) {
- if (devpriv->asics[i].irq)
- free_irq(devpriv->asics[i].irq, dev);
- }
- kfree(devpriv->sprivs);
+ pcmuio_reset(dev);
+
+ /* free the 2nd irq if used, the core will free the 1st one */
+ if (devpriv->irq2 && devpriv->irq2 != dev->irq)
+ free_irq(devpriv->irq2, dev);
}
comedi_legacy_detach(dev);
}
diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h
index 0d254a1b78a..25706531b88 100644
--- a/drivers/staging/comedi/drivers/plx9080.h
+++ b/drivers/staging/comedi/drivers/plx9080.h
@@ -29,13 +29,13 @@
/* descriptor block used for chained dma transfers */
struct plx_dma_desc {
- volatile uint32_t pci_start_addr;
- volatile uint32_t local_start_addr;
+ __le32 pci_start_addr;
+ __le32 local_start_addr;
/* transfer_size is in bytes, only first 23 bits of register are used */
- volatile uint32_t transfer_size;
+ __le32 transfer_size;
/* address of next descriptor (quad word aligned), plus some
* additional bits (see PLX_DMA0_DESCRIPTOR_REG) */
- volatile uint32_t next;
+ __le32 next;
};
/**********************************************************************
@@ -402,12 +402,9 @@ static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel)
udelay(1);
dma_status = readb(dma_cs_addr);
}
- if (i == timeout) {
- printk
- ("plx9080: cancel() timed out waiting for dma %i done clear\n",
- channel);
+ if (i == timeout)
return -ETIMEDOUT;
- }
+
/* disable and abort channel */
writeb(PLX_DMA_ABORT_BIT, dma_cs_addr);
/* wait for dma done bit */
@@ -416,12 +413,8 @@ static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel)
udelay(1);
dma_status = readb(dma_cs_addr);
}
- if (i == timeout) {
- printk
- ("plx9080: cancel() timed out waiting for dma %i done set\n",
- channel);
+ if (i == timeout)
return -ETIMEDOUT;
- }
return 0;
}
diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c
deleted file mode 100644
index 2ae4ee15704..00000000000
--- a/drivers/staging/comedi/drivers/poc.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- comedi/drivers/poc.c
- Mini-drivers for POC (Piece of Crap) boards
- Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>
- Copyright (C) 2001 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: poc
-Description: Generic driver for very simple devices
-Author: ds
-Devices: [Keithley Metrabyte] DAC-02 (dac02)
-Updated: Sat, 16 Mar 2002 17:34:48 -0800
-Status: unknown
-
-This driver is indended to support very simple ISA-based devices,
-including:
- dac02 - Keithley DAC-02 analog output board
-
-Configuration options:
- [0] - I/O port base
-*/
-
-#include <linux/module.h>
-#include "../comedidev.h"
-
-struct boarddef_struct {
- const char *name;
- unsigned int iosize;
- int (*setup) (struct comedi_device *);
- int type;
- int n_chan;
- int n_bits;
- int (*winsn) (struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
- int (*rinsn) (struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
- int (*insnbits) (struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
- const struct comedi_lrange *range;
-};
-
-struct poc_private {
- unsigned int ao_readback[32];
-};
-
-static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct poc_private *devpriv = dev->private;
- int chan;
-
- chan = CR_CHAN(insn->chanspec);
- data[0] = devpriv->ao_readback[chan];
-
- return 1;
-}
-
-/* DAC-02 registers */
-#define DAC02_LSB(a) (2 * a)
-#define DAC02_MSB(a) (2 * a + 1)
-
-static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct poc_private *devpriv = dev->private;
- int temp;
- int chan;
- int output;
-
- chan = CR_CHAN(insn->chanspec);
- devpriv->ao_readback[chan] = data[0];
- output = data[0];
-#ifdef wrong
- /* convert to complementary binary if range is bipolar */
- if ((CR_RANGE(insn->chanspec) & 0x2) == 0)
- output = ~output;
-#endif
- temp = (output << 4) & 0xf0;
- outb(temp, dev->iobase + DAC02_LSB(chan));
- temp = (output >> 4) & 0xff;
- outb(temp, dev->iobase + DAC02_MSB(chan));
-
- return 1;
-}
-
-static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- const struct boarddef_struct *board = comedi_board(dev);
- struct poc_private *devpriv;
- struct comedi_subdevice *s;
- int ret;
-
- ret = comedi_request_region(dev, it->options[0], board->iosize);
- if (ret)
- return ret;
-
- ret = comedi_alloc_subdevices(dev, 1);
- if (ret)
- return ret;
-
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
- /* analog output subdevice */
- s = &dev->subdevices[0];
- s->type = board->type;
- s->n_chan = board->n_chan;
- s->maxdata = (1 << board->n_bits) - 1;
- s->range_table = board->range;
- s->insn_write = board->winsn;
- s->insn_read = board->rinsn;
- s->insn_bits = board->insnbits;
- if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO)
- s->subdev_flags = SDF_WRITABLE;
-
- return 0;
-}
-
-static const struct boarddef_struct boards[] = {
- {
- .name = "dac02",
- .iosize = 8,
- /* .setup = dac02_setup, */
- .type = COMEDI_SUBD_AO,
- .n_chan = 2,
- .n_bits = 12,
- .winsn = dac02_ao_winsn,
- .rinsn = readback_insn,
- .range = &range_unknown,
- },
-};
-
-static struct comedi_driver poc_driver = {
- .driver_name = "poc",
- .module = THIS_MODULE,
- .attach = poc_attach,
- .detach = comedi_legacy_detach,
- .board_name = &boards[0].name,
- .num_names = ARRAY_SIZE(boards),
- .offset = sizeof(boards[0]),
-};
-module_comedi_driver(poc_driver);
-
-MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index 96a46954b3c..b3bbec0a0d2 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -214,7 +214,6 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id)
s->async->events |=
COMEDI_CB_EOA | COMEDI_CB_OVERFLOW;
dev_warn(dev->class_dev, "data lost\n");
- daqp_ai_cancel(dev, s);
break;
}
@@ -222,7 +221,7 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id)
data |= inb(dev->iobase + DAQP_FIFO) << 8;
data ^= 0x8000;
- comedi_buf_put(s->async, data);
+ comedi_buf_put(s, data);
/* If there's a limit, decrement it
* and stop conversion if zero
@@ -231,7 +230,6 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id)
if (devpriv->count > 0) {
devpriv->count--;
if (devpriv->count == 0) {
- daqp_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
break;
}
@@ -244,13 +242,12 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id)
if (loop_limit <= 0) {
dev_warn(dev->class_dev,
"loop_limit reached in daqp_interrupt()\n");
- daqp_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
}
s->async->events |= COMEDI_CB_BLOCK;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
}
return IRQ_HANDLED;
}
@@ -376,7 +373,7 @@ static int daqp_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
int err = 0;
- int tmp;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -438,19 +435,15 @@ static int daqp_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
- daqp_ns_to_timer(&cmd->scan_begin_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->scan_begin_arg)
- err++;
+ arg = cmd->scan_begin_arg;
+ daqp_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
- daqp_ns_to_timer(&cmd->convert_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->convert_arg)
- err++;
+ arg = cmd->convert_arg;
+ daqp_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
}
if (err)
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 44c8712ed9e..d55c5893203 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -237,20 +237,6 @@
/* The board support a channel list up to the FIFO length (1K or 8K) */
#define RTD_MAX_CHANLIST 128 /* max channel list that we allow */
-/* tuning for ai/ao instruction done polling */
-#ifdef FAST_SPIN
-#define WAIT_QUIETLY /* as nothing, spin on done bit */
-#define RTD_ADC_TIMEOUT 66000 /* 2 msec at 33mhz bus rate */
-#define RTD_DAC_TIMEOUT 66000
-#define RTD_DMA_TIMEOUT 33000 /* 1 msec */
-#else
-/* by delaying, power and electrical noise are reduced somewhat */
-#define WAIT_QUIETLY udelay(1)
-#define RTD_ADC_TIMEOUT 2000 /* in usec */
-#define RTD_DAC_TIMEOUT 2000 /* in usec */
-#define RTD_DMA_TIMEOUT 1000 /* in usec */
-#endif
-
/*======================================================================
Board specific stuff
======================================================================*/
@@ -495,8 +481,6 @@ static unsigned short rtd_convert_chan_gain(struct comedi_device *dev,
case AREF_OTHER: /* ??? */
break;
}
- /*printk ("chan=%d r=%d a=%d -> 0x%x\n",
- chan, range, aref, r); */
return r;
}
@@ -564,21 +548,27 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev)
return fifo_size;
}
-/*
- "instructions" read/write data in "one-shot" or "software-triggered"
- mode (simplest case).
- This doesn't use interrupts.
+static int rtd_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct rtd_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readl(devpriv->las0 + LAS0_ADC);
+ if (status & FS_ADC_NOT_EMPTY)
+ return 0;
+ return -EBUSY;
+}
- Note, we don't do any settling delays. Use a instruction list to
- select, delay, then read.
- */
static int rtd_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
struct rtd_private *devpriv = dev->private;
- int n, ii;
- int stat;
+ int ret;
+ int n;
/* clear any old fifo data */
writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
@@ -595,18 +585,12 @@ static int rtd_ai_rinsn(struct comedi_device *dev,
/* trigger conversion */
writew(0, devpriv->las0 + LAS0_ADC);
- for (ii = 0; ii < RTD_ADC_TIMEOUT; ++ii) {
- stat = readl(devpriv->las0 + LAS0_ADC);
- if (stat & FS_ADC_NOT_EMPTY) /* 1 -> not empty */
- break;
- WAIT_QUIETLY;
- }
- if (ii >= RTD_ADC_TIMEOUT)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, rtd_ai_eoc, 0);
+ if (ret)
+ return ret;
/* read data */
d = readw(devpriv->las1 + LAS1_ADC_FIFO);
- /*printk ("rtd520: Got 0x%x after %d usec\n", d, ii+1); */
d = d >> 3; /* low 3 bits are marker lines */
if (test_bit(0, devpriv->chan_is_bipolar))
/* convert to comedi unsigned data */
@@ -645,7 +629,7 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s,
d = comedi_offset_munge(s, d);
d &= s->maxdata;
- if (!comedi_buf_put(s->async, d))
+ if (!comedi_buf_put(s, d))
return -1;
if (devpriv->ai_count > 0) /* < 0, means read forever */
@@ -674,7 +658,7 @@ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s)
d = comedi_offset_munge(s, d);
d &= s->maxdata;
- if (!comedi_buf_put(s->async, d))
+ if (!comedi_buf_put(s, d))
return -1;
if (devpriv->ai_count > 0) /* < 0, means read forever */
@@ -692,7 +676,7 @@ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s)
static irqreturn_t rtd_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
- struct comedi_subdevice *s = &dev->subdevices[0];
+ struct comedi_subdevice *s = dev->read_subdev;
struct rtd_private *devpriv = dev->private;
u32 overrun;
u16 status;
@@ -795,7 +779,7 @@ static int rtd_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
int err = 0;
- int tmp;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -894,6 +878,8 @@ static int rtd_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 9);
}
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+
if (cmd->stop_src == TRIG_COUNT) {
/* TODO check for rounding error due to counter wrap */
} else {
@@ -907,31 +893,21 @@ static int rtd_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
- if (cmd->chanlist_len > RTD_MAX_CHANLIST) {
- cmd->chanlist_len = RTD_MAX_CHANLIST;
- err++;
- }
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
- rtd_ns_to_timer(&cmd->scan_begin_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->scan_begin_arg)
- err++;
-
+ arg = cmd->scan_begin_arg;
+ rtd_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
+
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
- rtd_ns_to_timer(&cmd->convert_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->convert_arg)
- err++;
-
- if (cmd->scan_begin_src == TRIG_TIMER
- && (cmd->scan_begin_arg
- < (cmd->convert_arg * cmd->scan_end_arg))) {
- cmd->scan_begin_arg =
- cmd->convert_arg * cmd->scan_end_arg;
- err++;
+ arg = cmd->convert_arg;
+ rtd_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
+
+ if (cmd->scan_begin_src == TRIG_TIMER) {
+ arg = cmd->convert_arg * cmd->scan_end_arg;
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ arg);
}
}
@@ -1119,9 +1095,22 @@ static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
-/*
- Output one (or more) analog values to a single port as fast as possible.
-*/
+static int rtd_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct rtd_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int bit = (chan == 0) ? FS_DAC1_NOT_EMPTY : FS_DAC2_NOT_EMPTY;
+ unsigned int status;
+
+ status = readl(devpriv->las0 + LAS0_ADC);
+ if (status & bit)
+ return 0;
+ return -EBUSY;
+}
+
static int rtd_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
@@ -1130,6 +1119,7 @@ static int rtd_ao_winsn(struct comedi_device *dev,
int i;
int chan = CR_CHAN(insn->chanspec);
int range = CR_RANGE(insn->chanspec);
+ int ret;
/* Configure the output range (table index matches the range values) */
writew(range & 7, devpriv->las0 +
@@ -1139,8 +1129,6 @@ static int rtd_ao_winsn(struct comedi_device *dev,
* very useful, but that's how the interface is defined. */
for (i = 0; i < insn->n; ++i) {
int val = data[i] << 3;
- int stat = 0; /* initialize to avoid bogus warning */
- int ii;
/* VERIFY: comedi range and offset conversions */
@@ -1160,16 +1148,9 @@ static int rtd_ao_winsn(struct comedi_device *dev,
devpriv->ao_readback[chan] = data[i];
- for (ii = 0; ii < RTD_DAC_TIMEOUT; ++ii) {
- stat = readl(devpriv->las0 + LAS0_ADC);
- /* 1 -> not empty */
- if (stat & ((0 == chan) ? FS_DAC1_NOT_EMPTY :
- FS_DAC2_NOT_EMPTY))
- break;
- WAIT_QUIETLY;
- }
- if (ii >= RTD_DAC_TIMEOUT)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, rtd_ao_eoc, 0);
+ if (ret)
+ return ret;
}
/* return the number of samples read/written */
@@ -1385,8 +1366,6 @@ static int rtd_auto_attach(struct comedi_device *dev,
if (dev->irq)
writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + PLX_INTRCS_REG);
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 0;
}
@@ -1427,7 +1406,7 @@ static int rtd520_pci_probe(struct pci_dev *dev,
return comedi_pci_auto_config(dev, &rtd520_driver, id->driver_data);
}
-static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = {
+static const struct pci_device_id rtd520_pci_table[] = {
{ PCI_VDEVICE(RTD, 0x7520), BOARD_DM7520 },
{ PCI_VDEVICE(RTD, 0x4520), BOARD_PCI4520 },
{ 0 }
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index e1f3671ac05..bd447b2add7 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -83,8 +83,6 @@
#define RTI800_IOSIZE 0x10
-#define RTI800_AI_TIMEOUT 100
-
static const struct comedi_lrange range_rti800_ai_10_bipolar = {
4, {
BIP_RANGE(10),
@@ -145,23 +143,21 @@ struct rti800_private {
unsigned char muxgain_bits;
};
-static int rti800_ai_wait_for_conversion(struct comedi_device *dev,
- int timeout)
+static int rti800_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
unsigned char status;
- int i;
- for (i = 0; i < timeout; i++) {
- status = inb(dev->iobase + RTI800_CSR);
- if (status & RTI800_CSR_OVERRUN) {
- outb(0, dev->iobase + RTI800_CLRFLAGS);
- return -EIO;
- }
- if (status & RTI800_CSR_DONE)
- return 0;
- udelay(1);
+ status = inb(dev->iobase + RTI800_CSR);
+ if (status & RTI800_CSR_OVERRUN) {
+ outb(0, dev->iobase + RTI800_CLRFLAGS);
+ return -EOVERFLOW;
}
- return -ETIME;
+ if (status & RTI800_CSR_DONE)
+ return 0;
+ return -EBUSY;
}
static int rti800_ai_insn_read(struct comedi_device *dev,
@@ -198,7 +194,8 @@ static int rti800_ai_insn_read(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
outb(0, dev->iobase + RTI800_CONVERT);
- ret = rti800_ai_wait_for_conversion(dev, RTI800_AI_TIMEOUT);
+
+ ret = comedi_timeout(dev, s, insn, rti800_ai_eoc, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index a3fa2a4baef..605a31d702e 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -1,45 +1,44 @@
/*
- comedi/drivers/rti802.c
- Hardware driver for Analog Devices RTI-802 board
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se>
-
- 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.
+ * rti802.c
+ * Comedi driver for Analog Devices RTI-802 board
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se>
+ *
+ * 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: rti802
-Description: Analog Devices RTI-802
-Author: Anders Blomdell <anders.blomdell@control.lth.se>
-Devices: [Analog Devices] RTI-802 (rti802)
-Status: works
-
-Configuration Options:
- [0] - i/o base
- [1] - unused
- [2] - dac#0 0=two's comp, 1=straight
- [3] - dac#0 0=bipolar, 1=unipolar
- [4] - dac#1 ...
- ...
- [17] - dac#7 ...
-*/
+ * Driver: rti802
+ * Description: Analog Devices RTI-802
+ * Author: Anders Blomdell <anders.blomdell@control.lth.se>
+ * Devices: (Analog Devices) RTI-802 [rti802]
+ * Status: works
+ *
+ * Configuration Options:
+ * [0] - i/o base
+ * [1] - unused
+ * [2,4,6,8,10,12,14,16] - dac#[0-7] 0=two's comp, 1=straight
+ * [3,5,7,9,11,13,15,17] - dac#[0-7] 0=bipolar, 1=unipolar
+ */
#include <linux/module.h>
#include "../comedidev.h"
-#define RTI802_SIZE 4
-
-#define RTI802_SELECT 0
-#define RTI802_DATALOW 1
-#define RTI802_DATAHIGH 2
+/*
+ * Register I/O map
+ */
+#define RTI802_SELECT 0x00
+#define RTI802_DATALOW 0x01
+#define RTI802_DATAHIGH 0x02
struct rti802_private {
enum {
@@ -51,34 +50,45 @@ struct rti802_private {
static int rti802_ao_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct rti802_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
int i;
for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
+ data[i] = devpriv->ao_readback[chan];
- return i;
+ return insn->n;
}
static int rti802_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct rti802_private *devpriv = dev->private;
- int i, d;
- int chan = CR_CHAN(insn->chanspec);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
+ int i;
+
+ outb(chan, dev->iobase + RTI802_SELECT);
for (i = 0; i < insn->n; i++) {
- d = devpriv->ao_readback[chan] = data[i];
+ val = data[i];
+
+ devpriv->ao_readback[chan] = val;
+
+ /* munge offset binary to two's complement if needed */
if (devpriv->dac_coding[chan] == dac_2comp)
- d ^= 0x800;
- outb(chan, dev->iobase + RTI802_SELECT);
- outb(d & 0xff, dev->iobase + RTI802_DATALOW);
- outb(d >> 8, dev->iobase + RTI802_DATAHIGH);
+ val = comedi_offset_munge(s, val);
+
+ outb(val & 0xff, dev->iobase + RTI802_DATALOW);
+ outb((val >> 8) & 0xff, dev->iobase + RTI802_DATAHIGH);
}
- return i;
+
+ return insn->n;
}
static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -88,7 +98,7 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
int i;
int ret;
- ret = comedi_request_region(dev, it->options[0], RTI802_SIZE);
+ ret = comedi_request_region(dev, it->options[0], 0x04);
if (ret)
return ret;
@@ -100,22 +110,21 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
+ /* Analog Output subdevice */
s = &dev->subdevices[0];
- /* ao subdevice */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE;
- s->maxdata = 0xfff;
- s->n_chan = 8;
- s->insn_read = rti802_ao_insn_read;
- s->insn_write = rti802_ao_insn_write;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->maxdata = 0xfff;
+ s->n_chan = 8;
+ s->insn_read = rti802_ao_insn_read;
+ s->insn_write = rti802_ao_insn_write;
s->range_table_list = devpriv->range_type_list;
for (i = 0; i < 8; i++) {
devpriv->dac_coding[i] = (it->options[3 + 2 * i])
- ? (dac_straight)
- : (dac_2comp);
+ ? (dac_straight) : (dac_2comp);
devpriv->range_type_list[i] = (it->options[2 + 2 * i])
- ? &range_unipolar10 : &range_bipolar10;
+ ? &range_unipolar10 : &range_bipolar10;
}
return 0;
@@ -130,5 +139,5 @@ static struct comedi_driver rti802_driver = {
module_comedi_driver(rti802_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for Analog Devices RTI-802 board");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index 9950f59b119..85d2b7a3c12 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -420,15 +420,28 @@ static int s526_ai_insn_config(struct comedi_device *dev,
return result;
}
+static int s526_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inw(dev->iobase + REG_ISR);
+ if (status & ISR_ADC_DONE)
+ return 0;
+ return -EBUSY;
+}
+
static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct s526_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
- int n, i;
+ int n;
unsigned short value;
unsigned int d;
- unsigned int status;
+ int ret;
/* Set configured delay, enable channel for this channel only,
* select "ADC read" channel, set "ADC start" bit. */
@@ -440,17 +453,12 @@ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
/* trigger conversion */
outw(value, dev->iobase + REG_ADC);
-#define TIMEOUT 100
/* wait for conversion to end */
- for (i = 0; i < TIMEOUT; i++) {
- status = inw(dev->iobase + REG_ISR);
- if (status & ISR_ADC_DONE) {
- outw(ISR_ADC_DONE, dev->iobase + REG_ISR);
- break;
- }
- }
- if (i == TIMEOUT)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, s526_ai_eoc, 0);
+ if (ret)
+ return ret;
+
+ outw(ISR_ADC_DONE, dev->iobase + REG_ISR);
/* read data */
d = inw(dev->iobase + REG_ADD);
@@ -604,7 +612,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->insn_bits = s526_dio_insn_bits;
s->insn_config = s526_dio_insn_config;
- return 1;
+ return 0;
}
static struct comedi_driver s526_driver = {
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index b486099b543..0838f8aa695 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -106,16 +106,16 @@ struct s626_private {
struct s626_enc_info {
/* Pointers to functions that differ for A and B counters: */
/* Return clock enable. */
- uint16_t(*get_enable)(struct comedi_device *dev,
+ uint16_t (*get_enable)(struct comedi_device *dev,
const struct s626_enc_info *k);
/* Return interrupt source. */
- uint16_t(*get_int_src)(struct comedi_device *dev,
+ uint16_t (*get_int_src)(struct comedi_device *dev,
const struct s626_enc_info *k);
/* Return preload trigger source. */
- uint16_t(*get_load_trig)(struct comedi_device *dev,
+ uint16_t (*get_load_trig)(struct comedi_device *dev,
const struct s626_enc_info *k);
/* Return standardized operating mode. */
- uint16_t(*get_mode)(struct comedi_device *dev,
+ uint16_t (*get_mode)(struct comedi_device *dev,
const struct s626_enc_info *k);
/* Generate soft index strobe. */
void (*pulse_index)(struct comedi_device *dev,
@@ -199,7 +199,7 @@ static bool s626_mc_test(struct comedi_device *dev,
static const struct comedi_lrange s626_range_table = {
2, {
BIP_RANGE(5),
- BIP_RANGE(10),
+ BIP_RANGE(10)
}
};
@@ -209,6 +209,8 @@ static const struct comedi_lrange s626_range_table = {
static void s626_debi_transfer(struct comedi_device *dev)
{
struct s626_private *devpriv = dev->private;
+ static const int timeout = 10000;
+ int i;
/* Initiate upload of shadow RAM to DEBI control register */
s626_mc_enable(dev, S626_MC2_UPLD_DEBI, S626_P_MC2);
@@ -217,12 +219,23 @@ static void s626_debi_transfer(struct comedi_device *dev)
* Wait for completion of upload from shadow RAM to
* DEBI control register.
*/
- while (!s626_mc_test(dev, S626_MC2_UPLD_DEBI, S626_P_MC2))
- ;
+ for (i = 0; i < timeout; i++) {
+ if (s626_mc_test(dev, S626_MC2_UPLD_DEBI, S626_P_MC2))
+ break;
+ udelay(1);
+ }
+ if (i == timeout)
+ comedi_error(dev,
+ "Timeout while uploading to DEBI control register.");
/* Wait until DEBI transfer is done */
- while (readl(devpriv->mmio + S626_P_PSR) & S626_PSR_DEBI_S)
- ;
+ for (i = 0; i < timeout; i++) {
+ if (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_DEBI_S))
+ break;
+ udelay(1);
+ }
+ if (i == timeout)
+ comedi_error(dev, "DEBI transfer timeout.");
}
/*
@@ -282,10 +295,24 @@ static void s626_debi_replace(struct comedi_device *dev, unsigned int addr,
/* ************** EEPROM ACCESS FUNCTIONS ************** */
-static uint32_t s626_i2c_handshake(struct comedi_device *dev, uint32_t val)
+static int s626_i2c_handshake_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ bool status;
+
+ status = s626_mc_test(dev, S626_MC2_UPLD_IIC, S626_P_MC2);
+ if (status)
+ return 0;
+ return -EBUSY;
+}
+
+static int s626_i2c_handshake(struct comedi_device *dev, uint32_t val)
{
struct s626_private *devpriv = dev->private;
unsigned int ctrl;
+ int ret;
/* Write I2C command to I2C Transfer Control shadow register */
writel(val, devpriv->mmio + S626_P_I2CCTRL);
@@ -295,8 +322,9 @@ static uint32_t s626_i2c_handshake(struct comedi_device *dev, uint32_t val)
* wait for upload confirmation.
*/
s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2);
- while (!s626_mc_test(dev, S626_MC2_UPLD_IIC, S626_P_MC2))
- ;
+ ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0);
+ if (ret)
+ return ret;
/* Wait until I2C bus transfer is finished or an error occurs */
do {
@@ -351,14 +379,57 @@ static const uint8_t s626_trimadrs[] = {
0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63
};
+enum {
+ s626_send_dac_wait_not_mc1_a2out,
+ s626_send_dac_wait_ssr_af2_out,
+ s626_send_dac_wait_fb_buffer2_msb_00,
+ s626_send_dac_wait_fb_buffer2_msb_ff
+};
+
+static int s626_send_dac_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct s626_private *devpriv = dev->private;
+ unsigned int status;
+
+ switch (context) {
+ case s626_send_dac_wait_not_mc1_a2out:
+ status = readl(devpriv->mmio + S626_P_MC1);
+ if (!(status & S626_MC1_A2OUT))
+ return 0;
+ break;
+ case s626_send_dac_wait_ssr_af2_out:
+ status = readl(devpriv->mmio + S626_P_SSR);
+ if (status & S626_SSR_AF2_OUT)
+ return 0;
+ break;
+ case s626_send_dac_wait_fb_buffer2_msb_00:
+ status = readl(devpriv->mmio + S626_P_FB_BUFFER2);
+ if (!(status & 0xff000000))
+ return 0;
+ break;
+ case s626_send_dac_wait_fb_buffer2_msb_ff:
+ status = readl(devpriv->mmio + S626_P_FB_BUFFER2);
+ if (status & 0xff000000)
+ return 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return -EBUSY;
+}
+
/*
* Private helper function: Transmit serial data to DAC via Audio
* channel 2. Assumes: (1) TSL2 slot records initialized, and (2)
* dacpol contains valid target image.
*/
-static void s626_send_dac(struct comedi_device *dev, uint32_t val)
+static int s626_send_dac(struct comedi_device *dev, uint32_t val)
{
struct s626_private *devpriv = dev->private;
+ int ret;
/* START THE SERIAL CLOCK RUNNING ------------- */
@@ -404,8 +475,12 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val)
* Done by polling the DMAC enable flag; this flag is automatically
* cleared when the transfer has finished.
*/
- while (readl(devpriv->mmio + S626_P_MC1) & S626_MC1_A2OUT)
- ;
+ ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc,
+ s626_send_dac_wait_not_mc1_a2out);
+ if (ret) {
+ comedi_error(dev, "DMA transfer timeout.");
+ return ret;
+ }
/* START THE OUTPUT STREAM TO THE TARGET DAC -------------------- */
@@ -425,8 +500,12 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val)
* finished transferring the DAC's data DWORD from the output FIFO
* to the output buffer register.
*/
- while (!(readl(devpriv->mmio + S626_P_SSR) & S626_SSR_AF2_OUT))
- ;
+ ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc,
+ s626_send_dac_wait_ssr_af2_out);
+ if (ret) {
+ comedi_error(dev, "TSL timeout waiting for slot 1 to execute.");
+ return ret;
+ }
/*
* Set up to trap execution at slot 0 when the TSL sequencer cycles
@@ -466,8 +545,13 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val)
* from 0xFF to 0x00, which slot 0 causes to happen by shifting
* out/in on SD2 the 0x00 that is always referenced by slot 5.
*/
- while (readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000)
- ;
+ ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc,
+ s626_send_dac_wait_fb_buffer2_msb_00);
+ if (ret) {
+ comedi_error(dev,
+ "TSL timeout waiting for slot 0 to execute.");
+ return ret;
+ }
}
/*
* Either (1) we were too late setting the slot 0 trap; the TSL
@@ -486,14 +570,19 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val)
* the next DAC write. This is detected when FB_BUFFER2 MSB changes
* from 0x00 to 0xFF.
*/
- while (!(readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000))
- ;
+ ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc,
+ s626_send_dac_wait_fb_buffer2_msb_ff);
+ if (ret) {
+ comedi_error(dev, "TSL timeout waiting for slot 0 to execute.");
+ return ret;
+ }
+ return 0;
}
/*
* Private helper function: Write setpoint to an application DAC channel.
*/
-static void s626_set_dac(struct comedi_device *dev, uint16_t chan,
+static int s626_set_dac(struct comedi_device *dev, uint16_t chan,
int16_t dacdata)
{
struct s626_private *devpriv = dev->private;
@@ -556,10 +645,10 @@ static void s626_set_dac(struct comedi_device *dev, uint16_t chan,
val |= ((uint32_t)(chan & 1) << 15); /* Address the DAC channel
* within the device. */
val |= (uint32_t)dacdata; /* Include DAC setpoint data. */
- s626_send_dac(dev, val);
+ return s626_send_dac(dev, val);
}
-static void s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan,
+static int s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan,
uint8_t dac_data)
{
struct s626_private *devpriv = dev->private;
@@ -606,17 +695,22 @@ static void s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan,
* Address the DAC channel within the trimdac device.
* Include DAC setpoint data.
*/
- s626_send_dac(dev, (chan << 8) | dac_data);
+ return s626_send_dac(dev, (chan << 8) | dac_data);
}
-static void s626_load_trim_dacs(struct comedi_device *dev)
+static int s626_load_trim_dacs(struct comedi_device *dev)
{
uint8_t i;
+ int ret;
/* Copy TrimDac setpoint values from EEPROM to TrimDacs. */
- for (i = 0; i < ARRAY_SIZE(s626_trimchan); i++)
- s626_write_trim_dac(dev, i,
+ for (i = 0; i < ARRAY_SIZE(s626_trimchan); i++) {
+ ret = s626_write_trim_dac(dev, i,
s626_i2c_read(dev, s626_trimadrs[i]));
+ if (ret)
+ return ret;
+ }
+ return 0;
}
/* ****** COUNTER FUNCTIONS ******* */
@@ -1534,7 +1628,6 @@ static bool s626_handle_eos_interrupt(struct comedi_device *dev)
readaddr++;
/* put data into read buffer */
- /* comedi_buf_put(async, tempdata); */
cfc_write_to_buffer(s, tempdata);
}
@@ -1614,12 +1707,13 @@ static irqreturn_t s626_irq_handler(int irq, void *d)
static void s626_reset_adc(struct comedi_device *dev, uint8_t *ppl)
{
struct s626_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_cmd *cmd = &s->async->cmd;
uint32_t *rps;
uint32_t jmp_adrs;
uint16_t i;
uint16_t n;
uint32_t local_ppl;
- struct comedi_cmd *cmd = &dev->subdevices->async->cmd;
/* Stop RPS program in case it is currently running */
s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1);
@@ -1845,6 +1939,20 @@ static int s626_ai_rinsn(struct comedi_device *dev,
}
#endif
+static int s626_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ struct s626_private *devpriv = dev->private;
+ unsigned int status;
+
+ status = readl(devpriv->mmio + S626_P_PSR);
+ if (status & S626_PSR_GPIO2)
+ return 0;
+ return -EBUSY;
+}
+
static int s626_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -1855,6 +1963,7 @@ static int s626_ai_insn_read(struct comedi_device *dev,
uint16_t adc_spec = 0;
uint32_t gpio_image;
uint32_t tmp;
+ int ret;
int n;
/*
@@ -1896,8 +2005,9 @@ static int s626_ai_insn_read(struct comedi_device *dev,
*/
/* Wait for ADC done */
- while (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_GPIO2))
- ;
+ ret = comedi_timeout(dev, s, insn, s626_ai_eoc, 0);
+ if (ret)
+ return ret;
/* Fetch ADC data */
if (n != 0) {
@@ -1933,8 +2043,9 @@ static int s626_ai_insn_read(struct comedi_device *dev,
/* Wait for the data to arrive in FB BUFFER 1 register. */
/* Wait for ADC done */
- while (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_GPIO2))
- ;
+ ret = comedi_timeout(dev, s, insn, s626_ai_eoc, 0);
+ if (ret)
+ return ret;
/* Fetch ADC data from audio interface's input shift register. */
@@ -1964,9 +2075,12 @@ static int s626_ai_load_polllist(uint8_t *ppl, struct comedi_cmd *cmd)
}
static int s626_ai_inttrig(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int trignum)
+ struct comedi_subdevice *s,
+ unsigned int trig_num)
{
- if (trignum != 0)
+ struct comedi_cmd *cmd = &s->async->cmd;
+
+ if (trig_num != cmd->start_arg)
return -EINVAL;
/* Start executing the RPS program */
@@ -1984,7 +2098,7 @@ static int s626_ai_inttrig(struct comedi_device *dev,
* Also, it should adjust ns so that it cooresponds to the actual time
* that the device will use.
*/
-static int s626_ns_to_timer(int *nanosec, int round_mode)
+static int s626_ns_to_timer(unsigned int *nanosec, int round_mode)
{
int divider, base;
@@ -2079,12 +2193,6 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (cmd == NULL)
return -EINVAL;
- if (dev->irq == 0) {
- comedi_error(dev,
- "s626_ai_cmd: cannot run command without an irq");
- return -EIO;
- }
-
s626_ai_load_polllist(ppl, cmd);
devpriv->ai_cmd_running = 1;
devpriv->ai_convert_count = 0;
@@ -2098,7 +2206,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* interval
*/
k = &s626_enc_chan_info[5];
- tick = s626_ns_to_timer((int *)&cmd->scan_begin_arg,
+ tick = s626_ns_to_timer(&cmd->scan_begin_arg,
cmd->flags & TRIG_ROUND_MASK);
/* load timer value and enable interrupt */
@@ -2121,7 +2229,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* interval
*/
k = &s626_enc_chan_info[4];
- tick = s626_ns_to_timer((int *)&cmd->convert_arg,
+ tick = s626_ns_to_timer(&cmd->convert_arg,
cmd->flags & TRIG_ROUND_MASK);
/* load timer value and enable interrupt */
@@ -2180,7 +2288,7 @@ static int s626_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
int err = 0;
- int tmp;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -2208,12 +2316,18 @@ static int s626_ai_cmdtest(struct comedi_device *dev,
if (err)
return 2;
- /* step 3: make sure arguments are trivially compatible */
+ /* Step 3: check if arguments are trivially valid */
- if (cmd->start_src != TRIG_EXT)
+ switch (cmd->start_src) {
+ case TRIG_NOW:
+ case TRIG_INT:
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
- if (cmd->start_src == TRIG_EXT)
+ break;
+ case TRIG_EXT:
err |= cfc_check_trigger_arg_max(&cmd->start_arg, 39);
+ break;
+ }
+
if (cmd->scan_begin_src == TRIG_EXT)
err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 39);
if (cmd->convert_src == TRIG_EXT)
@@ -2257,24 +2371,20 @@ static int s626_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
- s626_ns_to_timer((int *)&cmd->scan_begin_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->scan_begin_arg)
- err++;
+ arg = cmd->scan_begin_arg;
+ s626_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
+
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
- s626_ns_to_timer((int *)&cmd->convert_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->convert_arg)
- err++;
- if (cmd->scan_begin_src == TRIG_TIMER &&
- cmd->scan_begin_arg < cmd->convert_arg *
- cmd->scan_end_arg) {
- cmd->scan_begin_arg = cmd->convert_arg *
- cmd->scan_end_arg;
- err++;
+ arg = cmd->convert_arg;
+ s626_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
+
+ if (cmd->scan_begin_src == TRIG_TIMER) {
+ arg = cmd->convert_arg * cmd->scan_end_arg;
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ arg);
}
}
@@ -2304,6 +2414,7 @@ static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
{
struct s626_private *devpriv = dev->private;
int i;
+ int ret;
uint16_t chan = CR_CHAN(insn->chanspec);
int16_t dacdata;
@@ -2312,7 +2423,9 @@ static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[i];
dacdata -= (0x1fff);
- s626_set_dac(dev, chan, dacdata);
+ ret = s626_set_dac(dev, chan, dacdata);
+ if (ret)
+ return ret;
}
return i;
@@ -2548,12 +2661,13 @@ static int s626_allocate_dma_buffers(struct comedi_device *dev)
return 0;
}
-static void s626_initialize(struct comedi_device *dev)
+static int s626_initialize(struct comedi_device *dev)
{
struct s626_private *devpriv = dev->private;
dma_addr_t phys_buf;
uint16_t chan;
int i;
+ int ret;
/* Enable DEBI and audio pins, enable I2C interface */
s626_mc_enable(dev, S626_MC1_DEBI | S626_MC1_AUDIO | S626_MC1_I2C,
@@ -2587,8 +2701,9 @@ static void s626_initialize(struct comedi_device *dev)
writel(S626_I2C_CLKSEL | S626_I2C_ABORT,
devpriv->mmio + S626_P_I2CSTAT);
s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2);
- while (!(readl(devpriv->mmio + S626_P_MC2) & S626_MC2_UPLD_IIC))
- ;
+ ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0);
+ if (ret)
+ return ret;
/*
* Per SAA7146 data sheet, write to STATUS
@@ -2597,8 +2712,9 @@ static void s626_initialize(struct comedi_device *dev)
for (i = 0; i < 2; i++) {
writel(S626_I2C_CLKSEL, devpriv->mmio + S626_P_I2CSTAT);
s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2);
- while (!s626_mc_test(dev, S626_MC2_UPLD_IIC, S626_P_MC2))
- ;
+ ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0);
+ if (ret)
+ return ret;
}
/*
@@ -2645,6 +2761,7 @@ static void s626_initialize(struct comedi_device *dev)
* a defined state after a PCI reset.
*/
{
+ struct comedi_subdevice *s = dev->read_subdev;
uint8_t poll_list;
uint16_t adc_data;
uint16_t start_val;
@@ -2656,7 +2773,7 @@ static void s626_initialize(struct comedi_device *dev)
s626_reset_adc(dev, &poll_list);
/* Get initial ADC value */
- s626_ai_rinsn(dev, dev->subdevices, NULL, data);
+ s626_ai_rinsn(dev, s, NULL, data);
start_val = data[0];
/*
@@ -2670,7 +2787,7 @@ static void s626_initialize(struct comedi_device *dev)
* being unusually quiet or at the rail.
*/
for (index = 0; index < 500; index++) {
- s626_ai_rinsn(dev, dev->subdevices, NULL, data);
+ s626_ai_rinsn(dev, s, NULL, data);
adc_data = data[0];
if (adc_data != start_val)
break;
@@ -2753,7 +2870,9 @@ static void s626_initialize(struct comedi_device *dev)
* sometimes causes the first few TrimDAC writes to malfunction.
*/
s626_load_trim_dacs(dev);
- s626_load_trim_dacs(dev);
+ ret = s626_load_trim_dacs(dev);
+ if (ret)
+ return ret;
/*
* Manually init all gate array hardware in case this is a soft
@@ -2767,8 +2886,11 @@ static void s626_initialize(struct comedi_device *dev)
* Init all DAC outputs to 0V and init all DAC setpoint and
* polarity images.
*/
- for (chan = 0; chan < S626_DAC_CHANNELS; chan++)
- s626_set_dac(dev, chan, 0);
+ for (chan = 0; chan < S626_DAC_CHANNELS; chan++) {
+ ret = s626_set_dac(dev, chan, 0);
+ if (ret)
+ return ret;
+ }
/* Init counters */
s626_counters_init(dev);
@@ -2784,6 +2906,8 @@ static void s626_initialize(struct comedi_device *dev)
/* Initialize the digital I/O subsystem */
s626_dio_init(dev);
+
+ return 0;
}
static int s626_auto_attach(struct comedi_device *dev,
@@ -2833,7 +2957,7 @@ static int s626_auto_attach(struct comedi_device *dev,
s = &dev->subdevices[0];
/* analog input subdevice */
s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_CMD_READ;
+ s->subdev_flags = SDF_READABLE | SDF_DIFF;
s->n_chan = S626_ADC_CHANNELS;
s->maxdata = 0x3fff;
s->range_table = &s626_range_table;
@@ -2841,6 +2965,7 @@ static int s626_auto_attach(struct comedi_device *dev,
s->insn_read = s626_ai_insn_read;
if (dev->irq) {
dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
s->do_cmd = s626_ai_cmd;
s->do_cmdtest = s626_ai_cmdtest;
s->cancel = s626_ai_cancel;
@@ -2903,9 +3028,9 @@ static int s626_auto_attach(struct comedi_device *dev,
s->insn_read = s626_enc_insn_read;
s->insn_write = s626_enc_insn_write;
- s626_initialize(dev);
-
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
+ ret = s626_initialize(dev);
+ if (ret)
+ return ret;
return 0;
}
@@ -2965,7 +3090,7 @@ static int s626_pci_probe(struct pci_dev *dev,
* also subvendor:subdevice ids, because otherwise it will conflict with
* Philips SAA7146 media/dvb based cards.
*/
-static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = {
+static const struct pci_device_id s626_pci_table[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146,
0x6000, 0x0272) },
{ 0 }
diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c
index daee2f42bde..3bfa221faf4 100644
--- a/drivers/staging/comedi/drivers/skel.c
+++ b/drivers/staging/comedi/drivers/skel.c
@@ -142,6 +142,29 @@ static int skel_ns_to_timer(unsigned int *ns, int round)
}
/*
+ * This function doesn't require a particular form, this is just
+ * what happens to be used in some of the drivers. The comedi_timeout()
+ * helper uses this callback to check for the end-of-conversion while
+ * waiting for up to 1 second. This function should return 0 when the
+ * conversion is finished and -EBUSY to keep waiting. Any other errno
+ * will terminate comedi_timeout() and return that errno to the caller.
+ * If the timeout occurs, comedi_timeout() will return -ETIMEDOUT.
+ */
+static int skel_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ /* status = inb(dev->iobase + SKEL_STATUS); */
+ status = 1;
+ if (status)
+ return 0;
+ return -EBUSY;
+}
+
+/*
* "instructions" read/write data in "one-shot" or "software-triggered"
* mode.
*/
@@ -149,9 +172,9 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
const struct skel_board *thisboard = comedi_board(dev);
- int n, i;
+ int n;
unsigned int d;
- unsigned int status;
+ int ret;
/* a typical programming sequence */
@@ -165,18 +188,10 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
/* trigger conversion */
/* outw(0,dev->iobase + SKEL_CONVERT); */
-#define TIMEOUT 100
/* wait for conversion to end */
- for (i = 0; i < TIMEOUT; i++) {
- status = 1;
- /* status = inb(dev->iobase + SKEL_STATUS); */
- if (status)
- break;
- }
- if (i == TIMEOUT) {
- dev_warn(dev->class_dev, "ai timeout\n");
- return -ETIMEDOUT;
- }
+ ret = comedi_timeout(dev, s, insn, skel_ai_eoc, 0);
+ if (ret)
+ return ret;
/* read data */
/* d = inw(dev->iobase + SKEL_AI_DATA); */
@@ -205,7 +220,7 @@ static int skel_ai_cmdtest(struct comedi_device *dev,
struct comedi_cmd *cmd)
{
int err = 0;
- int tmp;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -271,24 +286,19 @@ static int skel_ai_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->scan_begin_src == TRIG_TIMER) {
- tmp = cmd->scan_begin_arg;
- skel_ns_to_timer(&cmd->scan_begin_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->scan_begin_arg)
- err++;
+ arg = cmd->scan_begin_arg;
+ skel_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
}
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
- skel_ns_to_timer(&cmd->convert_arg,
- cmd->flags & TRIG_ROUND_MASK);
- if (tmp != cmd->convert_arg)
- err++;
- if (cmd->scan_begin_src == TRIG_TIMER &&
- cmd->scan_begin_arg <
- cmd->convert_arg * cmd->scan_end_arg) {
- cmd->scan_begin_arg =
- cmd->convert_arg * cmd->scan_end_arg;
- err++;
+ arg = cmd->convert_arg;
+ skel_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
+
+ if (cmd->scan_begin_src == TRIG_TIMER) {
+ arg = cmd->convert_arg * cmd->scan_end_arg;
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ arg);
}
}
@@ -456,8 +466,6 @@ static int skel_common_attach(struct comedi_device *dev)
s->type = COMEDI_SUBD_UNUSED;
}
- dev_info(dev->class_dev, "skel: attached\n");
-
return 0;
}
@@ -698,7 +706,7 @@ static int skel_pci_probe(struct pci_dev *dev,
* This is used by modprobe to translate PCI IDs to drivers.
* Should only be used for PCI and ISA-PnP devices
*/
-static DEFINE_PCI_DEVICE_TABLE(skel_pci_table) = {
+static const struct pci_device_id skel_pci_table[] = {
{ PCI_VDEVICE(SKEL, 0x0100), BOARD_SKEL100 },
{ PCI_VDEVICE(SKEL, 0x0200), BOARD_SKEL200 },
{ 0 }
diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c
index df22a78d2b7..848c3080158 100644
--- a/drivers/staging/comedi/drivers/ssv_dnp.c
+++ b/drivers/staging/comedi/drivers/ssv_dnp.c
@@ -161,8 +161,7 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
outb(PCMR, CSCIR);
outb((inb(CSCDR) & 0xAA), CSCDR);
- dev_info(dev->class_dev, "%s: attached\n", dev->board_name);
- return 1;
+ return 0;
}
static void dnp_detach(struct comedi_device *dev)
diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c
index 93eec2fc254..adf7cb7086c 100644
--- a/drivers/staging/comedi/drivers/unioxx5.c
+++ b/drivers/staging/comedi/drivers/unioxx5.c
@@ -38,7 +38,6 @@ Devices: [Fastwel] UNIOxx-5 (unioxx5),
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/delay.h>
@@ -91,12 +90,14 @@ static int __unioxx5_define_chan_offset(int chan_num)
}
#if 0 /* not used? */
-static void __unioxx5_digital_config(struct unioxx5_subd_priv *usp, int mode)
+static void __unioxx5_digital_config(struct comedi_subdevice *s, int mode)
{
+ struct unioxx5_subd_priv *usp = s->private;
+ struct device *csdev = s->device->class_dev;
int i, mask;
mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00;
- printk("COMEDI: mode = %d\n", mask);
+ dev_dbg(csdev, "mode = %d\n", mask);
outb(1, usp->usp_iobase + 0);
@@ -135,15 +136,18 @@ static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel)
usp->usp_prev_cn_val[channel_offset - 1] = conf;
}
-static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp,
+static int __unioxx5_digital_read(struct comedi_subdevice *s,
unsigned int *data, int channel, int minor)
{
+ struct unioxx5_subd_priv *usp = s->private;
+ struct device *csdev = s->device->class_dev;
int channel_offset, mask = 1 << (channel & 0x07);
channel_offset = __unioxx5_define_chan_offset(channel);
if (channel_offset < 0) {
- pr_err("comedi%d: undefined channel %d. channel range is 0 .. 23\n",
- minor, channel);
+ dev_err(csdev,
+ "undefined channel %d. channel range is 0 .. 23\n",
+ channel);
return 0;
}
@@ -157,9 +161,11 @@ static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp,
return 1;
}
-static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
+static int __unioxx5_analog_read(struct comedi_subdevice *s,
unsigned int *data, int channel, int minor)
{
+ struct unioxx5_subd_priv *usp = s->private;
+ struct device *csdev = s->device->class_dev;
int module_no, read_ch;
char control;
@@ -168,8 +174,9 @@ static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
/* defining if given module can work on input */
if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) {
- pr_err("comedi%d: module in position %d with id 0x%02x is for output only",
- minor, module_no, usp->usp_module_type[module_no]);
+ dev_err(csdev,
+ "module in position %d with id 0x%02x is for output only",
+ module_no, usp->usp_module_type[module_no]);
return 0;
}
@@ -185,7 +192,7 @@ static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
/* if four bytes readding error occurs - return 0(false) */
if ((control & Rx4CA_ERR_MASK)) {
- printk("COMEDI: 4 bytes error\n");
+ dev_err(csdev, "4 bytes error\n");
return 0;
}
@@ -197,16 +204,19 @@ static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
return 1;
}
-static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp,
+static int __unioxx5_digital_write(struct comedi_subdevice *s,
unsigned int *data, int channel, int minor)
{
+ struct unioxx5_subd_priv *usp = s->private;
+ struct device *csdev = s->device->class_dev;
int channel_offset, val;
int mask = 1 << (channel & 0x07);
channel_offset = __unioxx5_define_chan_offset(channel);
if (channel_offset < 0) {
- pr_err("comedi%d: undefined channel %d. channel range is 0 .. 23\n",
- minor, channel);
+ dev_err(csdev,
+ "undefined channel %d. channel range is 0 .. 23\n",
+ channel);
return 0;
}
@@ -225,9 +235,11 @@ static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp,
return 1;
}
-static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
+static int __unioxx5_analog_write(struct comedi_subdevice *s,
unsigned int *data, int channel, int minor)
{
+ struct unioxx5_subd_priv *usp = s->private;
+ struct device *csdev = s->device->class_dev;
int module, i;
module = channel / 2; /* definig module number(0 .. 11) */
@@ -235,8 +247,9 @@ static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
/* defining if given module can work on output */
if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) {
- pr_err("comedi%d: module in position %d with id 0x%0x is for input only!\n",
- minor, module, usp->usp_module_type[module]);
+ dev_err(csdev,
+ "module in position %d with id 0x%0x is for input only!\n",
+ module, usp->usp_module_type[module]);
return 0;
}
@@ -273,10 +286,10 @@ static int unioxx5_subdev_read(struct comedi_device *dev,
type = usp->usp_module_type[channel / 2];
if (type == MODULE_DIGITAL) {
- if (!__unioxx5_digital_read(usp, data, channel, dev->minor))
+ if (!__unioxx5_digital_read(subdev, data, channel, dev->minor))
return -1;
} else {
- if (!__unioxx5_analog_read(usp, data, channel, dev->minor))
+ if (!__unioxx5_analog_read(subdev, data, channel, dev->minor))
return -1;
}
@@ -295,10 +308,10 @@ static int unioxx5_subdev_write(struct comedi_device *dev,
type = usp->usp_module_type[channel / 2];
if (type == MODULE_DIGITAL) {
- if (!__unioxx5_digital_write(usp, data, channel, dev->minor))
+ if (!__unioxx5_digital_write(subdev, data, channel, dev->minor))
return -1;
} else {
- if (!__unioxx5_analog_write(usp, data, channel, dev->minor))
+ if (!__unioxx5_analog_write(subdev, data, channel, dev->minor))
return -1;
}
@@ -318,16 +331,15 @@ static int unioxx5_insn_config(struct comedi_device *dev,
if (type != MODULE_DIGITAL) {
dev_err(dev->class_dev,
- "comedi%d: channel configuration accessible only for digital modules\n",
- dev->minor);
+ "channel configuration accessible only for digital modules\n");
return -1;
}
channel_offset = __unioxx5_define_chan_offset(channel);
if (channel_offset < 0) {
dev_err(dev->class_dev,
- "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
- dev->minor, channel);
+ "undefined channel %d. channel range is 0 .. 23\n",
+ channel);
return -1;
}
@@ -342,8 +354,7 @@ static int unioxx5_insn_config(struct comedi_device *dev,
flags |= mask;
break;
default:
- dev_err(dev->class_dev,
- "comedi%d: unknown flag\n", dev->minor);
+ dev_err(dev->class_dev, "unknown flag\n");
return -1;
}
@@ -435,9 +446,10 @@ static int unioxx5_attach(struct comedi_device *dev,
dev->iobase = iobase;
iobase += UNIOXX5_SUBDEV_BASE;
+ n_subd = 0;
- /* defining number of subdevices and getting they types (it must be 'g01') */
- for (i = n_subd = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) {
+ /* getting number of subdevices with types 'g01' */
+ for (i = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) {
id = inb(ba + 0xE);
num = inb(ba + 0xF);
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index da1d501d9e4..5f65e4213c6 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -80,7 +80,6 @@ sampling rate. If you sample two channels you get 4kHz and so on.
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/usb.h>
@@ -203,14 +202,11 @@ struct usbdux_private {
/* input buffer for single insn */
uint16_t *insn_buf;
- uint8_t ao_chanlist[USBDUX_NUM_AO_CHAN];
unsigned int ao_readback[USBDUX_NUM_AO_CHAN];
unsigned int high_speed:1;
unsigned int ai_cmd_running:1;
- unsigned int ai_continous:1;
unsigned int ao_cmd_running:1;
- unsigned int ao_continous:1;
unsigned int pwm_cmd_running:1;
/* number of samples to acquire */
@@ -267,7 +263,8 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb)
struct comedi_device *dev = urb->context;
struct comedi_subdevice *s = dev->read_subdev;
struct usbdux_private *devpriv = dev->private;
- int i, err, n;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ int i, err;
/* first we test if something unusual has just happened */
switch (urb->status) {
@@ -350,7 +347,7 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb)
devpriv->ai_counter = devpriv->ai_timer;
/* test, if we transmit only a fixed number of samples */
- if (!devpriv->ai_continous) {
+ if (cmd->stop_src == TRIG_COUNT) {
/* not continuous, fixed number of samples */
devpriv->ai_sample_count--;
/* all samples received? */
@@ -364,9 +361,8 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb)
}
}
/* get the data from the USB bus and hand it over to comedi */
- n = s->async->cmd.chanlist_len;
- for (i = 0; i < n; i++) {
- unsigned int range = CR_RANGE(s->async->cmd.chanlist[i]);
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int range = CR_RANGE(cmd->chanlist[i]);
uint16_t val = le16_to_cpu(devpriv->in_buf[i]);
/* bipolar data is two's-complement */
@@ -374,7 +370,7 @@ static void usbduxsub_ai_isoc_irq(struct urb *urb)
val ^= ((s->maxdata + 1) >> 1);
/* transfer data */
- err = comedi_buf_put(s->async, val);
+ err = comedi_buf_put(s, val);
if (unlikely(err == 0)) {
/* buffer overflow */
usbdux_ai_stop(dev, 0);
@@ -415,8 +411,8 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb)
struct comedi_device *dev = urb->context;
struct comedi_subdevice *s = dev->write_subdev;
struct usbdux_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
uint8_t *datap;
- int len;
int ret;
int i;
@@ -464,7 +460,7 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb)
devpriv->ao_counter = devpriv->ao_timer;
/* handle non continous acquisition */
- if (!devpriv->ao_continous) {
+ if (cmd->stop_src == TRIG_COUNT) {
/* fixed number of samples */
devpriv->ao_sample_count--;
if (devpriv->ao_sample_count < 0) {
@@ -479,13 +475,12 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb)
/* transmit data to the USB bus */
datap = urb->transfer_buffer;
- len = s->async->cmd.chanlist_len;
- *datap++ = len;
- for (i = 0; i < s->async->cmd.chanlist_len; i++) {
- unsigned int chan = devpriv->ao_chanlist[i];
+ *datap++ = cmd->chanlist_len;
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
unsigned short val;
- ret = comedi_buf_get(s->async, &val);
+ ret = comedi_buf_get(s, &val);
if (ret < 0) {
dev_err(dev->class_dev, "buffer underflow\n");
s->async->events |= (COMEDI_CB_EOA |
@@ -494,7 +489,7 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb)
/* pointer to the DA */
*datap++ = val & 0xff;
*datap++ = (val >> 8) & 0xff;
- *datap++ = chan;
+ *datap++ = chan << 6;
devpriv->ao_readback[chan] = val;
s->async->events |= COMEDI_CB_BLOCK;
@@ -693,15 +688,16 @@ static int receive_dux_commands(struct comedi_device *dev, unsigned int command)
static int usbdux_ai_inttrig(struct comedi_device *dev,
struct comedi_subdevice *s,
- unsigned int trignum)
+ unsigned int trig_num)
{
struct usbdux_private *devpriv = dev->private;
- int ret = -EINVAL;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ int ret;
- down(&devpriv->sem);
+ if (trig_num != cmd->start_arg)
+ return -EINVAL;
- if (trignum != 0)
- goto ai_trig_exit;
+ down(&devpriv->sem);
if (!devpriv->ai_cmd_running) {
devpriv->ai_cmd_running = 1;
@@ -778,10 +774,8 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (cmd->stop_src == TRIG_COUNT) {
/* data arrives as one packet */
devpriv->ai_sample_count = cmd->stop_arg;
- devpriv->ai_continous = 0;
} else {
/* continous acquisition */
- devpriv->ai_continous = 1;
devpriv->ai_sample_count = 0;
}
@@ -914,15 +908,16 @@ ao_write_exit:
static int usbdux_ao_inttrig(struct comedi_device *dev,
struct comedi_subdevice *s,
- unsigned int trignum)
+ unsigned int trig_num)
{
struct usbdux_private *devpriv = dev->private;
- int ret = -EINVAL;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ int ret;
- down(&devpriv->sem);
+ if (trig_num != cmd->start_arg)
+ return -EINVAL;
- if (trignum != 0)
- goto ao_trig_exit;
+ down(&devpriv->sem);
if (!devpriv->ao_cmd_running) {
devpriv->ao_cmd_running = 1;
@@ -1031,7 +1026,6 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
struct usbdux_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
int ret = -EBUSY;
- int i;
down(&devpriv->sem);
@@ -1041,12 +1035,6 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* set current channel of the running acquisition to zero */
s->async->cur_chan = 0;
- for (i = 0; i < cmd->chanlist_len; ++i) {
- unsigned int chan = CR_CHAN(cmd->chanlist[i]);
-
- devpriv->ao_chanlist[i] = chan << 6;
- }
-
/* we count in steps of 1ms (125us) */
/* 125us mode not used yet */
if (0) { /* (devpriv->high_speed) */
@@ -1078,10 +1066,8 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* data arrives as one packet */
devpriv->ao_sample_count = cmd->stop_arg;
}
- devpriv->ao_continous = 0;
} else {
/* continous acquisition */
- devpriv->ao_continous = 1;
devpriv->ao_sample_count = 0;
}
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index 9707dd1239c..85f9dcf5940 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -37,7 +37,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/usb.h>
@@ -138,7 +137,10 @@
* comedi constants
*/
static const struct comedi_lrange range_usbduxfast_ai_range = {
- 2, {BIP_RANGE(0.75), BIP_RANGE(0.5)}
+ 2, {
+ BIP_RANGE(0.75),
+ BIP_RANGE(0.5)
+ }
};
/*
@@ -152,7 +154,6 @@ struct usbduxfast_private {
uint8_t *duxbuf;
int8_t *inbuf;
short int ai_cmd_running; /* asynchronous command is running */
- short int ai_continous; /* continous acquisition */
long int ai_sample_count; /* number of samples to acquire */
int ignore; /* counter which ignores the first
buffers */
@@ -237,6 +238,7 @@ static void usbduxfast_ai_interrupt(struct urb *urb)
struct comedi_device *dev = urb->context;
struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
struct usb_device *usb = comedi_to_usb_dev(dev);
struct usbduxfast_private *devpriv = dev->private;
int n, err;
@@ -283,7 +285,7 @@ static void usbduxfast_ai_interrupt(struct urb *urb)
}
if (!devpriv->ignore) {
- if (!devpriv->ai_continous) {
+ if (cmd->stop_src == TRIG_COUNT) {
/* not continuous, fixed number of samples */
n = urb->actual_length / sizeof(uint16_t);
if (unlikely(devpriv->ai_sample_count < n)) {
@@ -370,7 +372,7 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_src(&cmd->start_src,
TRIG_NOW | TRIG_EXT | TRIG_INT);
err |= cfc_check_trigger_src(&cmd->scan_begin_src,
- TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT);
+ TRIG_FOLLOW | TRIG_EXT);
err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
@@ -396,8 +398,7 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev,
/* Step 3: check if arguments are trivially valid */
- if (cmd->start_src == TRIG_NOW)
- err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
if (!cmd->chanlist_len)
err |= -EINVAL;
@@ -422,9 +423,6 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, tmp);
}
- if (cmd->scan_begin_src == TRIG_TIMER)
- err |= -EINVAL;
-
/* stop source */
switch (cmd->stop_src) {
case TRIG_COUNT:
@@ -452,21 +450,20 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev,
static int usbduxfast_ai_inttrig(struct comedi_device *dev,
struct comedi_subdevice *s,
- unsigned int trignum)
+ unsigned int trig_num)
{
struct usbduxfast_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
int ret;
if (!devpriv)
return -EFAULT;
+ if (trig_num != cmd->start_arg)
+ return -EINVAL;
+
down(&devpriv->sem);
- if (trignum != 0) {
- dev_err(dev->class_dev, "invalid trignum\n");
- up(&devpriv->sem);
- return -EINVAL;
- }
if (!devpriv->ai_cmd_running) {
devpriv->ai_cmd_running = 1;
ret = usbduxfast_submit_urb(dev);
@@ -512,36 +509,28 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev,
*/
devpriv->ignore = PACKETS_TO_IGNORE;
- if (cmd->chanlist_len > 0) {
- gain = CR_RANGE(cmd->chanlist[0]);
- for (i = 0; i < cmd->chanlist_len; ++i) {
- chan = CR_CHAN(cmd->chanlist[i]);
- if (chan != i) {
- dev_err(dev->class_dev,
- "channels are not consecutive\n");
- up(&devpriv->sem);
- return -EINVAL;
- }
- if ((gain != CR_RANGE(cmd->chanlist[i]))
- && (cmd->chanlist_len > 3)) {
- dev_err(dev->class_dev,
- "gain must be the same for all channels\n");
- up(&devpriv->sem);
- return -EINVAL;
- }
- if (i >= NUMCHANNELS) {
- dev_err(dev->class_dev, "chanlist too long\n");
- break;
- }
+ gain = CR_RANGE(cmd->chanlist[0]);
+ for (i = 0; i < cmd->chanlist_len; ++i) {
+ chan = CR_CHAN(cmd->chanlist[i]);
+ if (chan != i) {
+ dev_err(dev->class_dev,
+ "channels are not consecutive\n");
+ up(&devpriv->sem);
+ return -EINVAL;
+ }
+ if ((gain != CR_RANGE(cmd->chanlist[i]))
+ && (cmd->chanlist_len > 3)) {
+ dev_err(dev->class_dev,
+ "gain must be the same for all channels\n");
+ up(&devpriv->sem);
+ return -EINVAL;
+ }
+ if (i >= NUMCHANNELS) {
+ dev_err(dev->class_dev, "chanlist too long\n");
+ break;
}
}
steps = 0;
- if (cmd->scan_begin_src == TRIG_TIMER) {
- dev_err(dev->class_dev,
- "scan_begin_src==TRIG_TIMER not valid\n");
- up(&devpriv->sem);
- return -EINVAL;
- }
if (cmd->convert_src == TRIG_TIMER)
steps = (cmd->convert_arg * 30) / 1000;
@@ -820,20 +809,11 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev,
up(&devpriv->sem);
return result;
}
- if (cmd->stop_src == TRIG_COUNT) {
+
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->ai_sample_count = cmd->stop_arg * cmd->scan_end_arg;
- if (devpriv->ai_sample_count < 1) {
- dev_err(dev->class_dev,
- "(cmd->stop_arg)*(cmd->scan_end_arg)<1, aborting\n");
- up(&devpriv->sem);
- return -EFAULT;
- }
- devpriv->ai_continous = 0;
- } else {
- /* continous acquisition */
- devpriv->ai_continous = 1;
+ else /* TRIG_NONE */
devpriv->ai_sample_count = 0;
- }
if ((cmd->start_src == TRIG_NOW) || (cmd->start_src == TRIG_EXT)) {
/* enable this acquisition operation */
@@ -846,12 +826,7 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev,
return ret;
}
s->async->inttrig = NULL;
- } else {
- /*
- * TRIG_INT
- * don't enable the acquision operation
- * wait for an internal signal
- */
+ } else { /* TRIG_INT */
s->async->inttrig = usbduxfast_ai_inttrig;
}
up(&devpriv->sem);
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index a5363ded366..ccc3ef7ba55 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -43,12 +43,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/fcntl.h>
#include <linux/compiler.h>
+#include <asm/unaligned.h>
#include "comedi_fc.h"
#include "../comedidev.h"
@@ -161,14 +161,11 @@ struct usbduxsigma_private {
/* input buffer for single insn */
uint8_t *insn_buf;
- uint8_t ao_chanlist[USBDUXSIGMA_NUM_AO_CHAN];
unsigned int ao_readback[USBDUXSIGMA_NUM_AO_CHAN];
unsigned high_speed:1;
unsigned ai_cmd_running:1;
- unsigned ai_continuous:1;
unsigned ao_cmd_running:1;
- unsigned ao_continuous:1;
unsigned pwm_cmd_running:1;
/* number of samples to acquire */
@@ -223,6 +220,7 @@ static void usbduxsigma_ai_urb_complete(struct urb *urb)
struct comedi_device *dev = urb->context;
struct usbduxsigma_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned int dio_state;
uint32_t val;
int ret;
@@ -301,7 +299,7 @@ static void usbduxsigma_ai_urb_complete(struct urb *urb)
/* timer zero, transfer measurements to comedi */
devpriv->ai_counter = devpriv->ai_timer;
- if (!devpriv->ai_continuous) {
+ if (cmd->stop_src == TRIG_COUNT) {
/* not continuous, fixed number of samples */
devpriv->ai_sample_count--;
if (devpriv->ai_sample_count < 0) {
@@ -314,7 +312,7 @@ static void usbduxsigma_ai_urb_complete(struct urb *urb)
}
/* get the data from the USB bus and hand it over to comedi */
- for (i = 0; i < s->async->cmd.chanlist_len; i++) {
+ for (i = 0; i < cmd->chanlist_len; i++) {
/* transfer data, note first byte is the DIO state */
val = be32_to_cpu(devpriv->in_buf[i+1]);
val &= 0x00ffffff; /* strip status byte */
@@ -360,8 +358,8 @@ static void usbduxsigma_ao_urb_complete(struct urb *urb)
struct comedi_device *dev = urb->context;
struct usbduxsigma_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->write_subdev;
+ struct comedi_cmd *cmd = &s->async->cmd;
uint8_t *datap;
- int len;
int ret;
int i;
@@ -403,7 +401,7 @@ static void usbduxsigma_ao_urb_complete(struct urb *urb)
/* timer zero, transfer from comedi */
devpriv->ao_counter = devpriv->ao_timer;
- if (!devpriv->ao_continuous) {
+ if (cmd->stop_src == TRIG_COUNT) {
/* not continuous, fixed number of samples */
devpriv->ao_sample_count--;
if (devpriv->ao_sample_count < 0) {
@@ -417,13 +415,12 @@ static void usbduxsigma_ao_urb_complete(struct urb *urb)
/* transmit data to the USB bus */
datap = urb->transfer_buffer;
- len = s->async->cmd.chanlist_len;
- *datap++ = len;
- for (i = 0; i < len; i++) {
- unsigned int chan = devpriv->ao_chanlist[i];
+ *datap++ = cmd->chanlist_len;
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
unsigned short val;
- ret = comedi_buf_get(s->async, &val);
+ ret = comedi_buf_get(s, &val);
if (ret < 0) {
dev_err(dev->class_dev, "buffer underflow\n");
s->async->events |= (COMEDI_CB_EOA |
@@ -596,10 +593,8 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev,
if (cmd->stop_src == TRIG_COUNT) {
/* data arrives as one packet */
devpriv->ai_sample_count = cmd->stop_arg;
- devpriv->ai_continuous = 0;
} else {
/* continuous acquisition */
- devpriv->ai_continuous = 1;
devpriv->ai_sample_count = 0;
}
@@ -663,12 +658,13 @@ static int usbduxsigma_receive_cmd(struct comedi_device *dev, int command)
static int usbduxsigma_ai_inttrig(struct comedi_device *dev,
struct comedi_subdevice *s,
- unsigned int trignum)
+ unsigned int trig_num)
{
struct usbduxsigma_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
int ret;
- if (trignum != 0)
+ if (trig_num != cmd->start_arg)
return -EINVAL;
down(&devpriv->sem);
@@ -738,7 +734,6 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev,
}
s->async->inttrig = NULL;
} else { /* TRIG_INT */
- /* wait for an internal signal and submit the urbs later */
s->async->inttrig = usbduxsigma_ai_inttrig;
}
@@ -793,7 +788,8 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev,
}
/* 32 bits big endian from the A/D converter */
- val = be32_to_cpu(*((uint32_t *)((devpriv->insn_buf) + 1)));
+ val = be32_to_cpu(get_unaligned((uint32_t
+ *)(devpriv->insn_buf + 1)));
val &= 0x00ffffff; /* strip status byte */
val ^= 0x00800000; /* convert to unsigned */
@@ -855,12 +851,13 @@ static int usbduxsigma_ao_insn_write(struct comedi_device *dev,
static int usbduxsigma_ao_inttrig(struct comedi_device *dev,
struct comedi_subdevice *s,
- unsigned int trignum)
+ unsigned int trig_num)
{
struct usbduxsigma_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
int ret;
- if (trignum != 0)
+ if (trig_num != cmd->start_arg)
return -EINVAL;
down(&devpriv->sem);
@@ -984,10 +981,8 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev,
*/
devpriv->ao_sample_count = cmd->stop_arg;
}
- devpriv->ao_continuous = 0;
} else {
/* continuous acquisition */
- devpriv->ao_continuous = 1;
devpriv->ao_sample_count = 0;
}
@@ -1003,14 +998,11 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev,
struct usbduxsigma_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
int ret;
- int i;
down(&devpriv->sem);
/* set current channel of the running acquisition to zero */
s->async->cur_chan = 0;
- for (i = 0; i < cmd->chanlist_len; ++i)
- devpriv->ao_chanlist[i] = CR_CHAN(cmd->chanlist[i]);
devpriv->ao_counter = devpriv->ao_timer;
@@ -1026,7 +1018,6 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev,
}
s->async->inttrig = NULL;
} else { /* TRIG_INT */
- /* wait for an internal signal and submit the urbs later */
s->async->inttrig = usbduxsigma_ao_inttrig;
}
@@ -1358,7 +1349,7 @@ static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan)
return ret;
/* 32 bits big endian from the A/D converter */
- val = be32_to_cpu(*((uint32_t *)((devpriv->insn_buf)+1)));
+ val = be32_to_cpu(get_unaligned((uint32_t *)(devpriv->insn_buf + 1)));
val &= 0x00ffffff; /* strip status byte */
val ^= 0x00800000; /* convert to unsigned */
@@ -1656,11 +1647,13 @@ static int usbduxsigma_auto_attach(struct comedi_device *dev,
}
offset = usbduxsigma_getstatusinfo(dev, 0);
- if (offset < 0)
+ if (offset < 0) {
dev_err(dev->class_dev,
- "Communication to USBDUXSIGMA failed! Check firmware and cabling\n");
+ "Communication to USBDUXSIGMA failed! Check firmware and cabling.\n");
+ return offset;
+ }
- dev_info(dev->class_dev, "attached, ADC_zero = %x\n", offset);
+ dev_info(dev->class_dev, "ADC_zero = %x\n", offset);
return 0;
}
diff --git a/drivers/staging/comedi/kcomedilib/Makefile b/drivers/staging/comedi/kcomedilib/Makefile
index 18ee99bdde0..3aff8ed08e2 100644
--- a/drivers/staging/comedi/kcomedilib/Makefile
+++ b/drivers/staging/comedi/kcomedilib/Makefile
@@ -1,3 +1,5 @@
+ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG
+
obj-$(CONFIG_COMEDI_KCOMEDILIB) += kcomedilib.o
kcomedilib-objs := kcomedilib_main.o
diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
index cd60677a3ed..8777f958c04 100644
--- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
+++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
@@ -35,35 +35,39 @@ MODULE_LICENSE("GPL");
struct comedi_device *comedi_open(const char *filename)
{
- struct comedi_device *dev;
+ struct comedi_device *dev, *retval = NULL;
unsigned int minor;
if (strncmp(filename, "/dev/comedi", 11) != 0)
return NULL;
- minor = simple_strtoul(filename + 11, NULL, 0);
+ if (kstrtouint(filename + 11, 0, &minor))
+ return NULL;
if (minor >= COMEDI_NUM_BOARD_MINORS)
return NULL;
- dev = comedi_dev_from_minor(minor);
-
- if (!dev || !dev->attached)
+ dev = comedi_dev_get_from_minor(minor);
+ if (!dev)
return NULL;
- if (!try_module_get(dev->driver->module))
- return NULL;
+ down_read(&dev->attach_lock);
+ if (dev->attached)
+ retval = dev;
+ else
+ retval = NULL;
+ up_read(&dev->attach_lock);
- return dev;
+ if (retval == NULL)
+ comedi_dev_put(dev);
+
+ return retval;
}
EXPORT_SYMBOL_GPL(comedi_open);
-int comedi_close(struct comedi_device *d)
+int comedi_close(struct comedi_device *dev)
{
- struct comedi_device *dev = (struct comedi_device *)d;
-
- module_put(dev->driver->module);
-
+ comedi_dev_put(dev);
return 0;
}
EXPORT_SYMBOL_GPL(comedi_close);
@@ -73,7 +77,14 @@ static int comedi_do_insn(struct comedi_device *dev,
unsigned int *data)
{
struct comedi_subdevice *s;
- int ret = 0;
+ int ret;
+
+ mutex_lock(&dev->mutex);
+
+ if (!dev->attached) {
+ ret = -EINVAL;
+ goto error;
+ }
/* a subdevice instruction */
if (insn->subdev >= dev->n_subdevices) {
@@ -120,6 +131,7 @@ static int comedi_do_insn(struct comedi_device *dev,
s->busy = NULL;
error:
+ mutex_unlock(&dev->mutex);
return ret;
}
@@ -169,9 +181,6 @@ int comedi_dio_bitfield2(struct comedi_device *dev, unsigned int subdev,
unsigned int shift;
int ret;
- if (subdev >= dev->n_subdevices)
- return -EINVAL;
-
base_channel = CR_CHAN(base_channel);
n_chan = comedi_get_n_channels(dev, subdev);
if (base_channel >= n_chan)
@@ -211,23 +220,33 @@ int comedi_find_subdevice_by_type(struct comedi_device *dev, int type,
unsigned int subd)
{
struct comedi_subdevice *s;
-
- if (subd > dev->n_subdevices)
- return -ENODEV;
-
- for (; subd < dev->n_subdevices; subd++) {
- s = &dev->subdevices[subd];
- if (s->type == type)
- return subd;
- }
- return -1;
+ int ret = -ENODEV;
+
+ down_read(&dev->attach_lock);
+ if (dev->attached)
+ for (; subd < dev->n_subdevices; subd++) {
+ s = &dev->subdevices[subd];
+ if (s->type == type) {
+ ret = subd;
+ break;
+ }
+ }
+ up_read(&dev->attach_lock);
+ return ret;
}
EXPORT_SYMBOL_GPL(comedi_find_subdevice_by_type);
int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice)
{
- struct comedi_subdevice *s = &dev->subdevices[subdevice];
+ int n;
+
+ down_read(&dev->attach_lock);
+ if (!dev->attached || subdevice >= dev->n_subdevices)
+ n = 0;
+ else
+ n = dev->subdevices[subdevice].n_chan;
+ up_read(&dev->attach_lock);
- return s->n_chan;
+ return n;
}
EXPORT_SYMBOL_GPL(comedi_get_n_channels);
diff --git a/drivers/staging/comedi/proc.c b/drivers/staging/comedi/proc.c
index ade00035d3b..91dea25b572 100644
--- a/drivers/staging/comedi/proc.c
+++ b/drivers/staging/comedi/proc.c
@@ -1,27 +1,26 @@
/*
- module/proc.c
- /proc interface for comedi
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1998 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.
-*/
+ * /proc interface for comedi
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1998 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.
+ */
/*
- This is some serious bloatware.
-
- Taken from Dave A.'s PCL-711 driver, 'cuz I thought it
- was cool.
-*/
+ * This is some serious bloatware.
+ *
+ * Taken from Dave A.'s PCL-711 driver, 'cuz I thought it
+ * was cool.
+ */
#include "comedidev.h"
#include "comedi_internal.h"
@@ -34,23 +33,24 @@ static int comedi_read(struct seq_file *m, void *v)
int devices_q = 0;
struct comedi_driver *driv;
- seq_printf(m,
- "comedi version " COMEDI_RELEASE "\n"
- "format string: %s\n",
- "\"%2d: %-20s %-20s %4d\", i, "
- "driver_name, board_name, n_subdevices");
+ seq_printf(m, "comedi version " COMEDI_RELEASE "\nformat string: %s\n",
+ "\"%2d: %-20s %-20s %4d\", i, driver_name, board_name, n_subdevices");
for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
- struct comedi_device *dev = comedi_dev_from_minor(i);
+ struct comedi_device *dev = comedi_dev_get_from_minor(i);
+
if (!dev)
continue;
+ down_read(&dev->attach_lock);
if (dev->attached) {
devices_q = 1;
seq_printf(m, "%2d: %-20s %-20s %4d\n",
i, dev->driver->driver_name,
dev->board_name, dev->n_subdevices);
}
+ up_read(&dev->attach_lock);
+ comedi_dev_put(dev);
}
if (!devices_q)
seq_puts(m, "no devices\n");
diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c
index 8fde55495d3..b6849545b81 100644
--- a/drivers/staging/comedi/range.c
+++ b/drivers/staging/comedi/range.c
@@ -83,8 +83,10 @@ int do_rangeinfo_ioctl(struct comedi_device *dev,
}
if (RANGE_LENGTH(it.range_type) != lr->length) {
- DPRINTK("wrong length %d should be %d (0x%08x)\n",
- RANGE_LENGTH(it.range_type), lr->length, it.range_type);
+ dev_dbg(dev->class_dev,
+ "wrong length %d should be %d (0x%08x)\n",
+ RANGE_LENGTH(it.range_type),
+ lr->length, it.range_type);
return -EINVAL;
}
@@ -123,7 +125,8 @@ static int aref_invalid(struct comedi_subdevice *s, unsigned int chanspec)
default:
break;
}
- DPRINTK("subdevice does not support aref %i", aref);
+ dev_dbg(s->device->class_dev, "subdevice does not support aref %i",
+ aref);
return 1;
}
@@ -140,28 +143,23 @@ int comedi_check_chanlist(struct comedi_subdevice *s, int n,
unsigned int chanspec;
int chan, range_len, i;
- if (s->range_table || s->range_table_list) {
- for (i = 0; i < n; i++) {
- chanspec = chanlist[i];
- chan = CR_CHAN(chanspec);
- if (s->range_table)
- range_len = s->range_table->length;
- else if (s->range_table_list && chan < s->n_chan)
- range_len = s->range_table_list[chan]->length;
- else
- range_len = 0;
- if (chan >= s->n_chan ||
- CR_RANGE(chanspec) >= range_len ||
- aref_invalid(s, chanspec)) {
- dev_warn(dev->class_dev,
- "bad chanlist[%d]=0x%08x chan=%d range length=%d\n",
- i, chanspec, chan, range_len);
- return -EINVAL;
- }
+ for (i = 0; i < n; i++) {
+ chanspec = chanlist[i];
+ chan = CR_CHAN(chanspec);
+ if (s->range_table)
+ range_len = s->range_table->length;
+ else if (s->range_table_list && chan < s->n_chan)
+ range_len = s->range_table_list[chan]->length;
+ else
+ range_len = 0;
+ if (chan >= s->n_chan ||
+ CR_RANGE(chanspec) >= range_len ||
+ aref_invalid(s, chanspec)) {
+ dev_warn(dev->class_dev,
+ "bad chanlist[%d]=0x%08x chan=%d range length=%d\n",
+ i, chanspec, chan, range_len);
+ return -EINVAL;
}
- } else {
- dev_err(dev->class_dev, "(bug) no range type list!\n");
- return -EINVAL;
}
return 0;
}