aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/comedi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi')
-rw-r--r--drivers/staging/comedi/Kconfig47
-rw-r--r--drivers/staging/comedi/TODO1
-rw-r--r--drivers/staging/comedi/comedi_buf.c103
-rw-r--r--drivers/staging/comedi/comedi_fops.c296
-rw-r--r--drivers/staging/comedi/comedi_internal.h8
-rw-r--r--drivers/staging/comedi/comedidev.h77
-rw-r--r--drivers/staging/comedi/drivers.c32
-rw-r--r--drivers/staging/comedi/drivers/8253.h109
-rw-r--r--drivers/staging/comedi/drivers/8255.c5
-rw-r--r--drivers/staging/comedi/drivers/8255.h4
-rw-r--r--drivers/staging/comedi/drivers/8255_pci.c37
-rw-r--r--drivers/staging/comedi/drivers/Makefile2
-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.c273
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c121
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c30
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_035.c14
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1032.c7
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1500.c26
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1564.c180
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2032.c26
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3120.c28
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3200.c36
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3501.c6
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3xxx.c110
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c22
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7x3x.c3
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c403
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c521
-rw-r--r--drivers/staging/comedi/drivers/adq12b.c31
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c558
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c2
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c10
-rw-r--r--drivers/staging/comedi/drivers/aio_aio12_8.c31
-rw-r--r--drivers/staging/comedi/drivers/aio_iiro_16.c2
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_common.c58
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236.c40
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc263.c2
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c354
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c430
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci263.c2
-rw-r--r--drivers/staging/comedi/drivers/c6xdigio.c491
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c151
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c223
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c203
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c52
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c4
-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.c35
-rw-r--r--drivers/staging/comedi/drivers/contec_pci_dio.c2
-rw-r--r--drivers/staging/comedi/drivers/dac02.c172
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c85
-rw-r--r--drivers/staging/comedi/drivers/das08.c35
-rw-r--r--drivers/staging/comedi/drivers/das08.h4
-rw-r--r--drivers/staging/comedi/drivers/das16.c112
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c144
-rw-r--r--drivers/staging/comedi/drivers/das1800.c198
-rw-r--r--drivers/staging/comedi/drivers/das6402.c672
-rw-r--r--drivers/staging/comedi/drivers/das800.c154
-rw-r--r--drivers/staging/comedi/drivers/dmm32at.c171
-rw-r--r--drivers/staging/comedi/drivers/dt2801.c2
-rw-r--r--drivers/staging/comedi/drivers/dt2811.c23
-rw-r--r--drivers/staging/comedi/drivers/dt2814.c38
-rw-r--r--drivers/staging/comedi/drivers/dt2815.c39
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c101
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c39
-rw-r--r--drivers/staging/comedi/drivers/dyna_pci10xx.c40
-rw-r--r--drivers/staging/comedi/drivers/fl512.c207
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c1111
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c109
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c21
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c891
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.h6
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c209
-rw-r--r--drivers/staging/comedi/drivers/me4000.c103
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c36
-rw-r--r--drivers/staging/comedi/drivers/mf6x4.c23
-rw-r--r--drivers/staging/comedi/drivers/mite.c47
-rw-r--r--drivers/staging/comedi/drivers/mite.h12
-rw-r--r--drivers/staging/comedi/drivers/mpc624.c30
-rw-r--r--drivers/staging/comedi/drivers/multiq3.c38
-rw-r--r--drivers/staging/comedi/drivers/ni_6527.c5
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c6
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c17
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c3
-rw-r--r--drivers/staging/comedi/drivers/ni_at_a2150.c144
-rw-r--r--drivers/staging/comedi/drivers/ni_at_ao.c8
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio16d.c63
-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_mio_common.c220
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c44
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c12
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.h8
-rw-r--r--drivers/staging/comedi/drivers/ni_tiocmd.c42
-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.c1496
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c1050
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c1532
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c6
-rw-r--r--drivers/staging/comedi/drivers/pcmad.c21
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c103
-rw-r--r--drivers/staging/comedi/drivers/pcmuio.c32
-rw-r--r--drivers/staging/comedi/drivers/plx9080.h8
-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.c128
-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.c266
-rw-r--r--drivers/staging/comedi/drivers/skel.c72
-rw-r--r--drivers/staging/comedi/drivers/ssv_dnp.c3
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c63
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c91
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c40
-rw-r--r--drivers/staging/comedi/kcomedilib/kcomedilib_main.c3
-rw-r--r--drivers/staging/comedi/proc.c48
-rw-r--r--drivers/staging/comedi/range.c37
130 files changed, 8577 insertions, 10709 deletions
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 89e25b4203a..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
@@ -1101,6 +1108,7 @@ config COMEDI_S626
config COMEDI_MITE
depends on HAS_DMA
+ select COMEDI_FC
tristate
config COMEDI_NI_TIOCMD
@@ -1179,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/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 924fce97798..df4a9c4bca3 100644
--- a/drivers/staging/comedi/comedi_buf.c
+++ b/drivers/staging/comedi/comedi_buf.c
@@ -61,6 +61,8 @@ 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);
@@ -68,8 +70,11 @@ static void __comedi_buf_free(struct comedi_device *dev,
async->prealloc_bufsz = 0;
}
- comedi_buf_map_put(async->buf_map);
+ 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,
@@ -80,6 +85,7 @@ static void __comedi_buf_alloc(struct comedi_device *dev,
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) {
@@ -92,8 +98,10 @@ static void __comedi_buf_alloc(struct comedi_device *dev,
if (!bm)
return;
- async->buf_map = bm;
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. */
@@ -127,7 +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)
@@ -150,9 +160,32 @@ int comedi_buf_map_put(struct comedi_buf_map *bm)
return 1;
}
-bool comedi_buf_is_mmapped(struct comedi_async *async)
+/* 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 = async->buf_map;
+ struct comedi_buf_map *bm = s->async->buf_map;
return bm && (atomic_read(&bm->refcount.refcount) > 1);
}
@@ -189,8 +222,10 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
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;
@@ -208,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;
@@ -236,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);
@@ -247,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);
@@ -290,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;
@@ -314,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)
@@ -334,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;
@@ -361,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;
/*
@@ -383,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)
@@ -436,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 c22c617b0da..9d99fb3c18a 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -238,9 +238,9 @@ comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor)
}
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)
@@ -251,7 +251,7 @@ static int resize_async_buffer(struct comedi_device *dev,
"subdevice is busy, cannot resize buffer\n");
return -EBUSY;
}
- if (comedi_buf_is_mmapped(async)) {
+ if (comedi_buf_is_mmapped(s)) {
dev_dbg(dev->class_dev,
"subdevice is mmapped, cannot resize buffer\n");
return -EBUSY;
@@ -297,7 +297,7 @@ static ssize_t max_read_buffer_kb_show(struct device *csdev,
mutex_unlock(&dev->mutex);
comedi_dev_put(dev);
- return snprintf(buf, PAGE_SIZE, "%i\n", size);
+ return snprintf(buf, PAGE_SIZE, "%u\n", size);
}
static ssize_t max_read_buffer_kb_store(struct device *csdev,
@@ -353,7 +353,7 @@ static ssize_t read_buffer_kb_show(struct device *csdev,
mutex_unlock(&dev->mutex);
comedi_dev_put(dev);
- return snprintf(buf, PAGE_SIZE, "%i\n", size);
+ return snprintf(buf, PAGE_SIZE, "%u\n", size);
}
static ssize_t read_buffer_kb_store(struct device *csdev,
@@ -380,7 +380,7 @@ static ssize_t read_buffer_kb_store(struct device *csdev,
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);
@@ -410,7 +410,7 @@ static ssize_t max_write_buffer_kb_show(struct device *csdev,
mutex_unlock(&dev->mutex);
comedi_dev_put(dev);
- return snprintf(buf, PAGE_SIZE, "%i\n", size);
+ return snprintf(buf, PAGE_SIZE, "%u\n", size);
}
static ssize_t max_write_buffer_kb_store(struct device *csdev,
@@ -466,7 +466,7 @@ static ssize_t write_buffer_kb_show(struct device *csdev,
mutex_unlock(&dev->mutex);
comedi_dev_put(dev);
- return snprintf(buf, PAGE_SIZE, "%i\n", size);
+ return snprintf(buf, PAGE_SIZE, "%u\n", size);
}
static ssize_t write_buffer_kb_store(struct device *csdev,
@@ -493,7 +493,7 @@ static ssize_t write_buffer_kb_store(struct device *csdev,
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);
@@ -583,7 +583,7 @@ 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;
@@ -635,7 +635,7 @@ static int is_device_busy(struct comedi_device *dev)
s = &dev->subdevices[i];
if (s->busy)
return 1;
- if (s->async && comedi_buf_is_mmapped(s->async))
+ if (s->async && comedi_buf_is_mmapped(s))
return 1;
}
@@ -668,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);
}
@@ -740,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;
}
@@ -992,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) {
@@ -1003,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:
@@ -1194,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
@@ -1207,8 +1213,14 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
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) {
@@ -1405,41 +1417,96 @@ 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))) {
+ 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) {
- dev_dbg(dev->class_dev, "%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) {
- dev_dbg(dev->class_dev, "%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) {
dev_dbg(dev->class_dev,
- "subdevice %i does not support commands\n", cmd.subdev);
+ "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) {
dev_dbg(dev->class_dev, "subdevice locked\n");
@@ -1452,13 +1519,6 @@ static int do_cmd_ioctl(struct comedi_device *dev,
return -EBUSY;
}
- /* 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 %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) {
dev_dbg(dev->class_dev, "channel/gain list too short %u < 1\n",
@@ -1468,25 +1528,11 @@ static int do_cmd_ioctl(struct comedi_device *dev,
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);
- async->cmd.chanlist = NULL;
- dev_dbg(dev->class_dev, "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) {
- dev_dbg(dev->class_dev, "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);
@@ -1511,7 +1557,7 @@ static int do_cmd_ioctl(struct comedi_device *dev,
goto cleanup;
}
- comedi_buf_reset(async);
+ comedi_buf_reset(s);
async->cb_mask =
COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
@@ -1554,63 +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))) {
- 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) {
- dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd.subdev);
- return -ENODEV;
- }
-
s = &dev->subdevices[cmd.subdev];
- if (s->type == COMEDI_SUBD_UNUSED) {
- dev_dbg(dev->class_dev, "%d not valid subdevice\n", cmd.subdev);
- return -EIO;
- }
-
- if (!s->do_cmd || !s->do_cmdtest) {
- dev_dbg(dev->class_dev,
- "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) {
- dev_dbg(dev->class_dev, "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);
- chanlist = NULL;
- dev_dbg(dev->class_dev,
- "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) {
- dev_dbg(dev->class_dev, "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);
@@ -1620,10 +1626,7 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
dev_dbg(dev->class_dev, "bad cmd address\n");
ret = -EFAULT;
- goto cleanup;
}
-cleanup:
- kfree(chanlist);
return ret;
}
@@ -1923,14 +1926,21 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
struct comedi_device *dev = file->private_data;
struct comedi_subdevice *s;
struct comedi_async *async;
- struct comedi_buf_map *bm;
+ struct comedi_buf_map *bm = NULL;
unsigned long start = vma->vm_start;
unsigned long size;
int n_pages;
int i;
int retval;
- 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) {
dev_dbg(dev->class_dev, "no driver attached\n");
@@ -1970,7 +1980,9 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
}
n_pages = size >> PAGE_SHIFT;
- bm = async->buf_map;
+
+ /* 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;
@@ -1994,7 +2006,8 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *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;
}
@@ -2016,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;
}
@@ -2123,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;
@@ -2154,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;
@@ -2216,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;
@@ -2259,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;
@@ -2314,46 +2327,12 @@ static int comedi_open(struct inode *inode, struct file *file)
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) {
- dev_dbg(dev->class_dev, "in request module\n");
- rc = -ENODEV;
- goto out;
- }
- 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)) {
dev_dbg(dev->class_dev, "not attached and not CAP_NET_ADMIN\n");
rc = -ENODEV;
goto out;
}
-ok:
if (dev->attached && dev->use_count == 0) {
if (!try_module_get(dev->driver->module)) {
rc = -ENOSYS;
@@ -2641,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 9a746570f16..e978c223f5b 100644
--- a/drivers/staging/comedi/comedi_internal.h
+++ b/drivers/staging/comedi/comedi_internal.h
@@ -15,11 +15,13 @@ 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);
-bool comedi_buf_is_mmapped(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);
-unsigned int comedi_buf_write_n_allocated(struct comedi_async *async);
+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;
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index f82bd4256d5..8f4e44bfbe0 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -61,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;
@@ -108,8 +108,6 @@ struct comedi_buf_map {
};
struct comedi_async {
- struct comedi_subdevice *subdevice;
-
void *prealloc_buf; /* pre-allocated buffer */
unsigned int prealloc_bufsz; /* buffer size, in bytes */
struct comedi_buf_map *buf_map; /* map of buffer pages */
@@ -146,8 +144,8 @@ struct comedi_async {
unsigned int cb_mask;
- 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;
@@ -182,7 +180,6 @@ 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;
@@ -202,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)
@@ -336,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);
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index 5b15033a94b..299726f39e2 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -155,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
@@ -228,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;
@@ -276,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;
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 48817f087d9..46113a37413 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -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)
@@ -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 8a57c3c1ade..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,
@@ -79,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[] = {
@@ -126,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,
},
};
@@ -163,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;
@@ -201,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) {
@@ -235,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;
}
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index 2706f583d8f..0757a82ddcf 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -24,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
@@ -53,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
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 bd05857b82f..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->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,7 +1510,7 @@ 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;
@@ -1574,10 +1519,8 @@ static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
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,7 +1532,7 @@ 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;
@@ -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 8c85a09d1c6..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;
@@ -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 ccd49211ea1..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,
},
};
diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c
index 0daa0ea63b5..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);
@@ -332,6 +332,7 @@ static int apci1032_auto_attach(struct comedi_device *dev,
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;
@@ -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 74f7ace8adb..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,
},
};
@@ -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_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c
index 6248284caaf..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,
@@ -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_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c
index c9b933cb598..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) {
@@ -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_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c
index 1e6fa56c516..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]) {
@@ -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 9868a5369af..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,
},
diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c
index 4cb69ec54c9..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];
diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
index ceadf8eff47..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;
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index 5c1413abc52..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;
diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c
index 6f622b4de69..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;
}
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index 363f2e42a27..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
@@ -138,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;
@@ -315,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;
@@ -467,18 +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;
/* 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);
}
@@ -486,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);
@@ -522,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,
@@ -540,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;
}
@@ -572,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;
@@ -589,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);
@@ -613,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)
@@ -717,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);
@@ -734,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;
}
@@ -906,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;
}
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index 4bdd9720e9e..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 :-(
@@ -320,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
@@ -341,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
@@ -353,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]; /*
@@ -372,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
@@ -411,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,
@@ -468,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;
@@ -552,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 */
@@ -571,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;
@@ -589,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 */
@@ -597,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;
@@ -705,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++) {
@@ -729,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));
@@ -783,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); */
@@ -847,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);
/*
@@ -874,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;
@@ -911,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;
}
@@ -931,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;
@@ -946,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;
@@ -957,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,
@@ -965,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,
@@ -996,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)
@@ -1037,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;
@@ -1066,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);
+
+ 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;
- (devpriv->int_ai_func) (dev, dev->read_subdev, int_adstat,
- int_amcc, int_daq);
+ 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;
@@ -1149,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);
@@ -1166,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 */
@@ -1222,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);
@@ -1260,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);
@@ -1278,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);
}
}
@@ -1331,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? */
@@ -1361,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",
@@ -1381,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",
@@ -1417,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
@@ -1428,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;
}
}
@@ -1443,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
@@ -1501,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 */
@@ -1521,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);
@@ -1535,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:
@@ -1549,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;
@@ -1581,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);
@@ -1591,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);
@@ -1611,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;
@@ -1630,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
@@ -1662,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) {
@@ -1678,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
@@ -1704,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 */
@@ -1721,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 */
@@ -1730,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 */
@@ -1766,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) &&
@@ -1788,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)
@@ -1799,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,
@@ -1825,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);
@@ -1846,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);
/*
@@ -1889,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;
@@ -1936,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)
@@ -1994,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]);
@@ -2038,7 +1911,7 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
/* Enable parity check for parity error */
if (!disable_irq && pcidev->irq) {
- ret = request_irq(pcidev->irq, interrupt_pci9118, IRQF_SHARED,
+ ret = request_irq(pcidev->irq, pci9118_interrupt, IRQF_SHARED,
dev->board_name, dev);
if (ret == 0)
dev->irq = pcidev->irq;
@@ -2097,23 +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;
- }
-
- pci9118_report_attach(dev, dev->irq);
return 0;
}
@@ -2176,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);
diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c
index 3190ef7d285..b4ea37704ea 100644
--- a/drivers/staging/comedi/drivers/adq12b.c
+++ b/drivers/staging/comedi/drivers/adq12b.c
@@ -94,8 +94,6 @@ 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, {
@@ -122,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);
@@ -151,13 +158,9 @@ 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);
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index d9ad2c0fdda..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 */
@@ -298,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 */
@@ -334,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];
- 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])
+ 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 (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,
@@ -401,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 */
@@ -411,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);
@@ -429,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 */
@@ -451,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;
}
/*
@@ -565,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);
}
}
@@ -721,100 +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->read_subdev;
- 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) {
- dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", 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) {
+ if (status & Status_FF) {
dev_dbg(dev->class_dev,
- "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
- pci171x_ai_cancel(dev, s);
+ "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;
+ }
+
+ comedi_buf_put(s, val & s->maxdata);
- if (s->async->cur_chan >= devpriv->ai_n_chan)
+ 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);
}
/*
@@ -824,76 +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]) {
- dev_dbg(dev->class_dev,
- "A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n",
- (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->read_subdev;
+ struct comedi_cmd *cmd = &s->async->cmd;
int m, samplesinbuf;
m = inw(dev->iobase + PCI171x_STATUS);
if (!(m & Status_FH)) {
dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
- pci171x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
return;
}
if (m & Status_FF) {
dev_dbg(dev->class_dev,
"A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
- pci171x_ai_cancel(dev, s);
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;
@@ -904,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);
}
/*
@@ -924,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 */
@@ -941,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;
@@ -1045,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 */
@@ -1094,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 */
+ /* Step 5: check channel list */
- if (cmd->chanlist) {
- if (!check_channel_list(dev, s, cmd->chanlist,
- cmd->chanlist_len))
- return 5; /* incorrect channels list */
- }
+ err |= pci171x_ai_check_chanlist(dev, s, cmd);
- 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;
-
-
- 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;
}
/*
@@ -1167,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 */
@@ -1292,7 +1178,6 @@ static int pci1710_auto_attach(struct comedi_device *dev,
s->do_cmd = pci171x_ai_cmd;
s->cancel = pci171x_ai_cancel;
}
- devpriv->i8254_osc_base = I8254_OSC_BASE_10MHZ;
subdev++;
}
@@ -1354,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;
}
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index 72394267ddf..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;
}
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index d4bd61d84da..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++;
}
diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c
index 68c3fb3226c..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;
}
@@ -247,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/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c
index 9c9559ffc64..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) {
@@ -516,28 +510,16 @@ static int dio200_subdev_intr_cmd(struct comedi_device *dev,
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_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index 31734e1142f..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)
@@ -361,39 +361,13 @@ static irqreturn_t pc236_interrupt(int irq, void *d)
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,
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 ae4048a624f..339c47c1eb9 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -377,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;
};
@@ -467,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,
@@ -531,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);
@@ -557,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;
@@ -583,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;
@@ -605,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)
@@ -627,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) {
/*
@@ -670,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;
@@ -691,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
@@ -704,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 */
@@ -731,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)
@@ -771,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. */
@@ -825,98 +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) {
- dev_dbg(dev->class_dev,
- "%s: entries in chanlist must contain no duplicate channels\n",
- __func__);
- }
- if (errors & range_err) {
- dev_dbg(dev->class_dev,
- "%s: entries in chanlist must all have the same range index\n",
- __func__);
- }
- 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;
@@ -924,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;
@@ -982,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;
}
@@ -1105,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;
@@ -1115,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;
@@ -1237,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.
*/
@@ -1399,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)
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index c08dfbbe406..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
@@ -799,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);
@@ -883,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);
@@ -951,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)
{
@@ -1063,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) {
- dev_dbg(dev->class_dev,
- "%s: channel numbers must increase\n",
- __func__);
- }
- if ((errors & range_err) != 0) {
- dev_dbg(dev->class_dev,
- "%s: channels must have the same range\n",
- __func__);
- }
- }
- }
+ /* 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;
@@ -1173,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);
@@ -1188,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. */
@@ -1210,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;
@@ -1263,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
@@ -1347,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);
@@ -1432,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;
@@ -1458,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 */
@@ -1550,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)
{
@@ -1738,136 +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) {
- dev_dbg(dev->class_dev,
- "%s: channel numbers must increase or sequence must repeat exactly\n",
- __func__);
- }
- if ((errors & rangepair_err) != 0) {
- dev_dbg(dev->class_dev,
- "%s: single-ended channel pairs must have the same range\n",
- __func__);
- }
- if ((errors & polarity_err) != 0) {
- dev_dbg(dev->class_dev,
- "%s: channel sequence ranges must be all bipolar or all unipolar\n",
- __func__);
- }
- if ((errors & aref_err) != 0) {
- dev_dbg(dev->class_dev,
- "%s: channel sequence analogue references must be all the same (single-ended or differential)\n",
- __func__);
- }
- if ((errors & diffchan_err) != 0) {
- dev_dbg(dev->class_dev,
- "%s: differential channel number out of range 0 to %u\n",
- __func__, (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;
@@ -1889,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)
@@ -2042,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);
@@ -2175,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;
@@ -2188,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;
@@ -2245,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;
@@ -2259,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 {
@@ -2310,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;
@@ -2461,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;
}
@@ -2762,14 +2718,14 @@ static int pci230_attach_common(struct comedi_device *dev,
/* 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)
diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c
index be28e6cbea2..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;
}
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index 5034f663eec..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,309 +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;
- WriteByteToHwPort(baseAddr, 0x70);
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0)
- && (timeout < C6XDIGIO_TIME_OUT)) {
+ do {
+ status = inb(dev->iobase + C6XDIGIO_STATUS_REG);
+ if ((status & 0x80) != context)
+ return 0;
timeout++;
- }
+ } while (timeout < C6XDIGIO_TIME_OUT);
- WriteByteToHwPort(baseAddr, 0x74);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
+ return -EBUSY;
+}
- WriteByteToHwPort(baseAddr, 0x70);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
+static int c6xdigio_write_data(struct comedi_device *dev,
+ unsigned int val, unsigned int status)
+{
+ outb_p(val, dev->iobase + C6XDIGIO_DATA_REG);
+ return c6xdigio_chk_status(dev, status);
+}
- WriteByteToHwPort(baseAddr, 0x0);
- timeout = 0;
- while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
- && (timeout < C6XDIGIO_TIME_OUT)) {
- timeout++;
- }
+static int c6xdigio_get_encoder_bits(struct comedi_device *dev,
+ unsigned int *bits,
+ unsigned int cmd,
+ unsigned int status)
+{
+ unsigned int val;
+
+ val = inb(dev->iobase + C6XDIGIO_STATUS_REG);
+ val >>= 3;
+ val &= 0x07;
+
+ *bits = val;
+ return c6xdigio_write_data(dev, cmd, status);
}
-static void C6X_pwmOutput(unsigned long baseAddr, unsigned channel, int value)
+static void c6xdigio_pwm_write(struct comedi_device *dev,
+ unsigned int chan, unsigned int val)
{
- unsigned ppcmd;
- union pwmcmdtype pwm;
- int timeout = 0;
- unsigned tmp;
-
- 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++;
- }
+ 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);
+}
- 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++;
- }
+static int c6xdigio_encoder_read(struct comedi_device *dev,
+ unsigned int chan)
+{
+ unsigned int cmd = C6XDIGIO_DATA_ENCODER | C6XDIGIO_DATA_CHAN(chan);
+ unsigned int val = 0;
+ unsigned int bits;
- WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb2);
- tmp = ReadByteFromHwPort(baseAddr + 1);
- while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
- tmp = ReadByteFromHwPort(baseAddr + 1);
- timeout++;
- }
+ c6xdigio_write_data(dev, cmd, 0x00);
- 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++;
- }
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80);
+ val |= (bits << 0);
- WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb4);
- 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);
- 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 | (1 << 2), 0x80);
+ val |= (bits << 6);
-}
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
+ val |= (bits << 9);
-static int C6X_encInput(unsigned long baseAddr, unsigned channel)
-{
- unsigned ppcmd;
- union encvaluetype enc;
- int timeout = 0;
- int tmp;
-
- enc.value = 0;
- if (channel == 0)
- ppcmd = 0x48;
- else
- ppcmd = 0x50;
-
- 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 | (1 << 2), 0x80);
+ val |= (bits << 12);
- 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 | (0 << 2), 0x00);
+ val |= (bits << 15);
- 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 | (1 << 2), 0x80);
+ val |= (bits << 18);
+
+ c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00);
+ val |= (bits << 21);
+
+ c6xdigio_write_data(dev, 0x00, 0x80);
- return enc.value ^ 0x800000;
+ return val;
}
-static void C6X_encResetAll(unsigned long baseAddr)
+static int c6xdigio_pwm_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- unsigned timeout = 0;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = (s->state >> (16 * chan)) & 0xffff;
+ int i;
- 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++;
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+ c6xdigio_pwm_write(dev, chan, val);
}
+
+ /*
+ * 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_pwmo_insn_write(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)
{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
int i;
- int chan = CR_CHAN(insn->chanspec);
- for (i = 0; i < insn->n; i++) {
- C6X_pwmOutput(dev->iobase, chan, data[i]);
- /* devpriv->ao_readback[chan] = data[i]; */
- }
- return i;
+ val = (s->state >> (16 * chan)) & 0xffff;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = val;
+
+ 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_encoder_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- int n;
- int chan = CR_CHAN(insn->chanspec);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
+ int i;
- for (n = 0; n < insn->n; n++)
- data[n] = (C6X_encInput(dev->iobase, chan) & 0xffffff);
+ for (i = 0; i < insn->n; i++) {
+ val = c6xdigio_encoder_read(dev, chan);
+
+ /* munge two's complement value to offset binary */
+ data[i] = comedi_offset_munge(s, val);
+ }
- return n;
+ return insn->n;
}
-static void board_init(struct comedi_device *dev)
+static void c6xdigio_init(struct comedi_device *dev)
{
- C6X_pwmInit(dev->iobase);
- C6X_encResetAll(dev->iobase);
+ /* 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[] = {
@@ -367,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;
@@ -380,27 +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_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->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;
}
@@ -420,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 9819be092f8..7377da1aff7 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -376,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)
@@ -385,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) {
@@ -415,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);
@@ -792,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)
@@ -799,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 */
@@ -835,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
@@ -851,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)
@@ -875,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;
@@ -921,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,
@@ -972,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)
@@ -1006,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)
@@ -1016,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;
@@ -1027,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)
@@ -1034,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 */
@@ -1077,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;
@@ -1137,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 */
@@ -1172,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)
{
@@ -1201,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;
@@ -1269,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);
@@ -1282,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;
@@ -1300,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,
@@ -1312,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)
@@ -1322,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;
@@ -1332,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);
@@ -1355,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;
}
@@ -1364,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,
@@ -1381,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;
}
@@ -1411,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;
}
@@ -1576,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;
}
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index 4fff1738e3f..035c3a17600 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -1664,15 +1664,36 @@ 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;
channel = CR_CHAN(insn->chanspec);
range = CR_RANGE(insn->chanspec);
@@ -1770,23 +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);
- if (thisboard->layout == LAYOUT_4020) {
- if (readw(devpriv->main_iobase +
- ADC_WRITE_PNTR_REG))
- break;
- } else {
- if (pipe_full_bits(bits))
- break;
- }
- udelay(1);
- }
- 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;
@@ -1987,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 */
@@ -2032,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);
@@ -2090,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;
@@ -2695,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;
@@ -2716,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;
@@ -2865,7 +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);
- 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)
@@ -3176,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;
}
@@ -3196,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);
@@ -3218,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;
}
@@ -3239,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 */
@@ -3277,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);
@@ -3307,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;
@@ -3816,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];
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index 8cca0518cfd..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;
}
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index 57295d189ff..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.
*/
@@ -85,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 */
@@ -118,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
@@ -133,17 +148,10 @@ 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)
- 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);
@@ -247,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;
}
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index 43a86630a66..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 = {
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 d539eaf53b6..67a09aa6b72 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -185,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;
@@ -199,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 +
@@ -225,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 */
@@ -277,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)
@@ -318,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;
@@ -418,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 323a7f39cd9..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;
}
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 ce153fcb8b2..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;
}
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index e5c0ee9a09c..c5e352fb555 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -201,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);
@@ -244,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) {
@@ -529,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/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 fee5facff8d..ec039fbff0f 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -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,6 +271,7 @@ 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;
/* disable interrupts and internal pacer */
@@ -278,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);
@@ -292,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;
@@ -308,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);
@@ -331,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;
@@ -356,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));
}
@@ -407,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 */
@@ -440,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;
}
}
@@ -449,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)
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index 320d95a5f47..859519026c4 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -547,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;
@@ -646,7 +646,6 @@ static void das1800_ai_handler(struct comedi_device *dev)
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 */
@@ -665,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 */
@@ -680,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,
@@ -737,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;
@@ -746,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;
@@ -763,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,
@@ -771,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 */
@@ -831,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;
@@ -968,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;
-}
+ /* 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);
-/* 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 */
- 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' */
@@ -1142,7 +1097,6 @@ 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;
@@ -1173,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 */
@@ -1476,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];
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index 43027ee500e..d18eea6c01a 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -1,309 +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;
+
+ unsigned int count;
+ unsigned int divider1;
+ unsigned int divider2;
- int das6402_ignoreirq;
+ 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;
- }
+ 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);
- das6402_ai_fifo_dregs(dev, s);
+ i8254_write(timer_iobase, 0, 0, devpriv->count);
+ i8254_write(timer_iobase, 0, 1, devpriv->divider1);
+ i8254_write(timer_iobase, 0, 2, devpriv->divider2);
- 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 */
- s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
+ } 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;
- 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);
+ /*
+ * If XFER mode is enabled, reading any DAC register
+ * will update both DAC's simultaneously.
+ */
+ inw(dev->iobase + DAS6402_AO_LSB_REG(chan));
- devpriv->ai_bytes_to_read = it->n * sizeof(short);
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
- /* um... ignoreirq is a nasty race condition */
- devpriv->das6402_ignoreirq = 0;
+ return insn->n;
+}
- outw_p(SCANL, dev->iobase + 2);
+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);
- return 0;
+ return insn->n;
}
-#endif
-static int board_init(struct comedi_device *dev)
+static int das6402_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct das6402_private *devpriv = dev->private;
- BYTE b;
+ if (comedi_dio_update_state(s, data))
+ outb(s->state, dev->iobase + DAS6402_DI_DO_REG);
- devpriv->das6402_ignoreirq = 1;
+ data[1] = s->state;
- outb(0x07, dev->iobase + 8);
+ return insn->n;
+}
- /* register 11 */
- outb_p(MODE, dev->iobase + 11);
- b = BIP | SEM | MODE | GAIN | FIFOHFULL;
- outb_p(b, dev->iobase + 11);
+static void das6402_reset(struct comedi_device *dev)
+{
+ struct das6402_private *devpriv = dev->private;
- /* 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 "Enhanced" mode */
+ outb(DAS6402_MODE_ENHANCED, dev->iobase + DAS6402_MODE_REG);
- /* register 9 */
- b = IRQ | CONVSRC | BURSTEN | INTE;
- outb_p(b, dev->iobase + 9);
+ /* enable 10MHz pacer clock */
+ das6402_set_extended(dev, DAS6402_STATUS_W_10MHZ);
- /* register 10 */
- b = TGSEL | TGEN;
- outb_p(b, dev->iobase + 10);
+ /* enable software conversion trigger */
+ outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG);
- b = 0x07;
- outb_p(b, dev->iobase + 8);
+ /* 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);
- das6402_setcounter(dev);
+ /* 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);
- outw_p(SCANL, dev->iobase + 2); /* reset card fifo */
+ /* 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);
- devpriv->das6402_ignoreirq = 0;
+ /* 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));
- return 0;
+ das6402_enable_counter(dev, false);
+
+ /* set all digital outputs low */
+ outb(0, dev->iobase + DAS6402_DI_DO_REG);
+
+ 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;
}
@@ -313,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 78a19629ff5..ad7a5d53b97 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -164,16 +164,29 @@ 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 */
@@ -190,26 +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)
- 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)
- 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);
@@ -236,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 */
@@ -318,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;
@@ -403,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;
@@ -439,14 +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)
- 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 */
@@ -457,12 +468,6 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
outb(0xff, dev->iobase + DMM32AT_CONV);
}
-/* 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;
}
@@ -503,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 */
@@ -525,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)
@@ -533,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. */
@@ -549,13 +568,9 @@ static int dmm32at_ao_winsn(struct comedi_device *dev,
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)
- 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);
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index d4d4e4b497d..4263014426f 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -545,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;
diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c
index 4271903facd..ba7c2ba618e 100644
--- a/drivers/staging/comedi/drivers/dt2811.c
+++ b/drivers/staging/comedi/drivers/dt2811.c
@@ -224,23 +224,32 @@ static const struct comedi_lrange *dac_range_types[] = {
&range_unipolar5
};
-#define DT2811_TIMEOUT 5
+static int dt2811_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
+{
+ unsigned int status;
+
+ status = inb(dev->iobase + DT2811_ADCSR);
+ if ((status & DT2811_ADBUSY) == 0)
+ return 0;
+ return -EBUSY;
+}
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;
diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c
index abad6e49c1c..904c9f0e4af 100644
--- a/drivers/staging/comedi/drivers/dt2814.c
+++ b/drivers/staging/comedi/drivers/dt2814.c
@@ -66,26 +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);
- udelay(10);
- if (status & DT2814_FINISH)
- break;
- }
- if (i >= DT2814_TIMEOUT)
- 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);
@@ -119,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 */
@@ -161,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;
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index ee24717821e..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,30 +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) {
- dev_dbg(dev->class_dev,
- "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) {
- dev_dbg(dev->class_dev,
- "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;
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 895f73a1902..c2a66dcf99f 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -63,7 +63,6 @@ Notes:
#include "comedi_fc.h"
-#define DT2821_TIMEOUT 100 /* 500 us */
#define DT2821_SIZE 0x10
/*
@@ -248,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);
@@ -328,7 +306,6 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev)
size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize);
if (size == 0) {
dev_err(dev->class_dev, "AO underrun\n");
- dt282x_ao_cancel(dev, s);
s->async->events |= COMEDI_CB_OVERFLOW;
return;
}
@@ -363,7 +340,7 @@ 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;
@@ -373,7 +350,6 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev)
devpriv->nread = 0;
}
if (!devpriv->nread) {
- dt282x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
return;
}
@@ -471,15 +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) {
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
@@ -492,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;
@@ -508,7 +482,8 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
handled = 1;
}
#endif
- comedi_event(dev, s);
+ cfc_handle_events(dev, s);
+ cfc_handle_events(dev, s_ao);
return IRQ_RETVAL(handled);
}
@@ -530,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
@@ -542,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? */
@@ -551,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 +
@@ -574,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 */
@@ -629,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;
@@ -646,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,
@@ -691,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,
@@ -818,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 */
@@ -845,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 */
@@ -858,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;
@@ -871,12 +876,14 @@ 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,
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index f52a4476cb7..4ab4de00592 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -322,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;
@@ -369,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;
}
@@ -418,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 */
@@ -468,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);
}
}
@@ -767,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;
}
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index f224825830b..e5593f8c740 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -57,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 */
@@ -82,18 +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;
- dev_dbg(dev->class_dev, "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;
}
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index a99ddf00ddc..4e410f3b0e2 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -1,27 +1,49 @@
/*
- 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
-*/
+ * 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];
};
@@ -38,72 +60,69 @@ static const struct comedi_lrange range_fl512 = {
}
};
-/*
- * 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)
@@ -112,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;
@@ -124,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 de60a2871d7..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,149 +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);
-
-#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];
@@ -207,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)
@@ -237,31 +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);
+
+ 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);
- writel(0, devpriv->plx9080_iobase + 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;
+ 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;
@@ -285,117 +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;
-
- 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++;
- }
- }
- 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);
-
- 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;
@@ -406,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));
@@ -433,17 +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;
}
- 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);
@@ -470,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;
@@ -490,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])
@@ -516,318 +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);
-
- 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);
-
- 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;
- }
- /* 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) {
- 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);
-
- if (dma0_status & PLX_DMA_EN_BIT)
- drain_dma_buffers(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_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);
- }
- 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);
- }
-
- if (hpdi_board_status & RX_OVERRUN_BIT) {
- comedi_error(dev, "rx fifo overrun");
- async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- }
-
- 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;
-
- 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,
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c
index 80539b2bea1..0b8b2162b76 100644
--- a/drivers/staging/comedi/drivers/icp_multi.c
+++ b/drivers/staging/comedi/drivers/icp_multi.c
@@ -171,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;
@@ -199,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;
-
- 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);
+ ret = comedi_timeout(dev, s, insn, icp_multi_ai_eoc, 0);
+ if (ret)
+ break;
- /* Clear data received */
- data[n] = 0;
-
- return -ETIME;
-
-conv_finish:
data[n] =
(readw(devpriv->io_addr + ICP_MULTI_AI) >> 4) & 0x0fff;
}
@@ -238,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,
@@ -246,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;
@@ -274,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);
@@ -565,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;
}
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 6100c12c164..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);
}
@@ -808,11 +807,11 @@ static int jr3_pci_pci_probe(struct pci_dev *dev,
}
static const struct pci_device_id 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) },
+ { 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 6b9846fd8c4..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,
};
@@ -140,7 +163,7 @@ static int ke_counter_pci_probe(struct pci_dev *dev,
}
static const struct pci_device_id ke_counter_pci_table[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) },
+ { 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 e739bcd66a0..25ce2f78db8 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -598,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;
}
@@ -934,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;
@@ -1091,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;
@@ -1112,9 +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;
-
if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) &
ME4000_IRQ_STATUS_BIT_AI_HF) {
/* Read status register to find out what happened */
@@ -1167,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
@@ -1212,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;
@@ -1395,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]) {
@@ -1402,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;
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index 7f668789640..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;
}
diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c
index 81b78e053f4..a4f7d6f138d 100644
--- a/drivers/staging/comedi/drivers/mf6x4.c
+++ b/drivers/staging/comedi/drivers/mf6x4.c
@@ -133,21 +133,18 @@ static int mf6x4_do_insn_bits(struct comedi_device *dev,
return insn->n;
}
-static int mf6x4_ai_wait_for_eoc(struct comedi_device *dev,
- unsigned int timeout)
+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 eolc;
+ unsigned int status;
- while (timeout--) {
- eolc = ioread32(devpriv->gpioc_R) & MF6X4_GPIOC_EOLC;
- if (eolc)
- return 0;
-
- udelay(1);
- }
-
- return -ETIME;
+ status = ioread32(devpriv->gpioc_R);
+ if (status & MF6X4_GPIOC_EOLC)
+ return 0;
+ return -EBUSY;
}
static int mf6x4_ai_insn_read(struct comedi_device *dev,
@@ -168,7 +165,7 @@ static int mf6x4_ai_insn_read(struct comedi_device *dev,
/* Trigger ADC conversion by reading ADSTART */
ioread16(devpriv->bar1_mem + MF6X4_ADSTART_R);
- ret = mf6x4_ai_wait_for_eoc(dev, 100);
+ ret = comedi_timeout(dev, s, insn, mf6x4_ai_eoc, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index 9c9a0ee432c..19c029acbc9 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -307,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;
@@ -333,7 +334,7 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring,
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;
}
@@ -525,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;
@@ -550,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;
}
@@ -593,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;
diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h
index bcf2f972376..e6e58e989b7 100644
--- a/drivers/staging/comedi/drivers/mite.h
+++ b/drivers/staging/comedi/drivers/mite.h
@@ -29,9 +29,9 @@
#define MAX_MITE_DMA_CHANNELS 8
struct mite_dma_descriptor {
- u32 count;
- u32 addr;
- u32 next;
+ __le32 count;
+ __le32 addr;
+ __le32 next;
u32 dar;
};
@@ -106,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);
@@ -120,7 +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);
+ 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 fe4621ea65c..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,7 +162,7 @@ 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:
@@ -170,15 +180,9 @@ 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)
- return -ETIMEDOUT;
+ ret = comedi_timeout(dev, s, insn, mpc624_ai_eoc, 0);
+ if (ret)
+ return ret;
/* Start reading data */
data_in = 0;
@@ -341,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 860fc81fb11..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;
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index 6e42001f686..9a139d6b8ef 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -439,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;
@@ -473,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)
@@ -491,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);
@@ -671,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;
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index df42e390617..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"
@@ -789,13 +790,7 @@ static void ni_660x_handle_gpct_interrupt(struct comedi_device *dev,
struct ni_gpct *counter = s->private;
ni_tio_handle_interrupt(counter, 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);
- }
+ cfc_handle_events(dev, s);
}
static irqreturn_t ni_660x_interrupt(int irq, void *d)
@@ -828,9 +823,9 @@ static int ni_660x_input_poll(struct comedi_device *dev,
/* lock to avoid race with comedi_poll */
spin_lock_irqsave(&devpriv->interrupt_lock, flags);
- mite_sync_input_dma(counter->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,
@@ -841,7 +836,7 @@ static int ni_660x_buf_change(struct comedi_device *dev,
struct ni_gpct *counter = s->private;
int ret;
- ret = mite_buf_change(mite_ring(devpriv, counter), s->async);
+ ret = mite_buf_change(mite_ring(devpriv, counter), s);
if (ret < 0)
return ret;
@@ -1187,7 +1182,7 @@ static int ni_660x_auto_attach(struct comedi_device *dev,
global_interrupt_config_bits |= Cascade_Int_Enable_Bit;
ni_660x_write_register(dev, 0, global_interrupt_config_bits,
NI660X_GLOBAL_INT_CFG);
- dev_info(dev->class_dev, "ni_660x: %s attached\n", dev->board_name);
+
return 0;
}
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index 8550fdc4ccd..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;
}
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index f83eb9ebe27..5bd19494dbf 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -184,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);
@@ -196,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;
}
@@ -249,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;
}
@@ -265,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);
@@ -290,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 */
@@ -342,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;
@@ -390,6 +402,7 @@ 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;
@@ -457,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;
@@ -488,13 +502,25 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
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);
@@ -524,30 +550,20 @@ 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;
- }
+ ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0);
+ if (ret)
+ return ret;
+
data[n] = inw(dev->iobase + FIFO_DATA_REG);
data[n] ^= 0x8000;
}
@@ -680,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];
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_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index e8cd5ddb85c..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 {
@@ -222,7 +221,7 @@ static irqreturn_t atmio16d_interrupt(int irq, void *d)
struct comedi_device *dev = d;
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;
@@ -448,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);
@@ -473,26 +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) {
- outw(0, dev->iobase + AD_CLEAR_REG);
- return -ETIME;
- }
- }
- /* end waiting, now check if it timed out */
- if (t == ATMIO16D_TIMEOUT)
- return -ETIME;
+ ret = comedi_timeout(dev, s, insn, atmio16d_ai_eoc, 0);
+ if (ret)
+ return ret;
+
+ /* 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;
@@ -723,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
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_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index 457b88481db..7ffdcc07ef9 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -256,7 +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);
-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,
@@ -272,15 +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);
#ifdef PCIDMA
static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
+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);
@@ -687,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) {
@@ -858,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);
}
@@ -871,7 +877,7 @@ static void mite_handle_b_linkc(struct mite_struct *mite,
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
if (devpriv->ao_mite_chan)
- mite_sync_output_dma(devpriv->ao_mite_chan, s->async);
+ mite_sync_output_dma(devpriv->ao_mite_chan, s);
spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
}
@@ -937,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)
{
@@ -974,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
}
@@ -1033,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;
}
@@ -1048,8 +1027,7 @@ 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) {
@@ -1076,7 +1054,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
if ((status & AI_STOP_St))
ni_handle_eos(dev, s);
- ni_event(dev, s);
+ cfc_handle_events(dev, s);
}
static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status)
@@ -1151,7 +1129,7 @@ static void handle_b_interrupt(struct comedi_device *dev,
}
#endif
- ni_event(dev, s);
+ cfc_handle_events(dev, s);
}
#ifndef PCIDMA
@@ -1171,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;
@@ -1181,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++;
@@ -1222,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;
@@ -1252,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;
@@ -1490,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
@@ -1507,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;
}
}
@@ -1527,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) {
@@ -1567,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) {
@@ -2102,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 */
@@ -2141,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) {
@@ -2532,30 +2513,28 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
#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;
}
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,
@@ -2732,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;
}
}
@@ -2968,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
@@ -3239,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;
}
@@ -3250,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 */
@@ -3280,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) {
@@ -3326,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;
}
@@ -3461,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 */
@@ -3506,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;
@@ -3552,25 +3541,32 @@ static int ni_cdio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
retval = ni_request_cdo_mite_channel(dev);
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);
@@ -3645,7 +3641,7 @@ 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
@@ -3662,7 +3658,7 @@ static void handle_cdio_interrupt(struct comedi_device *dev)
M_Offset_CDIO_Command);
/* 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,
@@ -4282,10 +4278,14 @@ 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);
- else
+ if (board->has_8255) {
+ ret = subdev_8255_init(dev, s, ni_8255_callback,
+ (unsigned long)dev);
+ if (ret)
+ return ret;
+ } else {
s->type = COMEDI_SUBD_UNUSED;
+ }
/* formerly general purpose counter/timer device, but no longer used */
s = &dev->subdevices[NI_UNUSED_SUBDEV];
@@ -4393,6 +4393,9 @@ static int ni_E_init(struct comedi_device *dev)
&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)];
@@ -4483,7 +4486,6 @@ static int ni_E_init(struct comedi_device *dev)
ni_writeb(0x0, M_Offset_AO_Calibration);
}
- printk("\n");
return 0;
}
@@ -4992,9 +4994,9 @@ static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *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;
@@ -5002,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
/*
*
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 30c46a3c176..5fc74d6ff6a 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -263,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,
@@ -353,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;
@@ -373,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);
@@ -419,7 +405,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
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 |
@@ -461,8 +447,8 @@ 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);
+ comedi_buf_put(s, data1);
+ comedi_buf_put(s, data2);
flags = readb(devpriv->mite->daq_io_addr +
Group_1_Flags);
}
@@ -501,7 +487,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
}
out:
- ni_pcidio_event(dev, s);
+ cfc_handle_events(dev, s);
#if 0
if (!tag) {
writeb(0x03,
@@ -550,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 */
@@ -609,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)
@@ -773,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) {
@@ -787,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);
@@ -818,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;
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 0ed98045587..89300dc78e3 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -1551,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,
@@ -1560,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;
@@ -1573,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;
@@ -1587,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;
@@ -1601,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;
@@ -1614,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;
diff --git a/drivers/staging/comedi/drivers/ni_tio.h b/drivers/staging/comedi/drivers/ni_tio.h
index 68378dab4e7..1056bf001e5 100644
--- a/drivers/staging/comedi/drivers/ni_tio.h
+++ b/drivers/staging/comedi/drivers/ni_tio.h
@@ -115,10 +115,10 @@ 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;
diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c
index 7d64f8892f0..2557ab48cb6 100644
--- a/drivers/staging/comedi/drivers/ni_tiocmd.c
+++ b/drivers/staging/comedi/drivers/ni_tiocmd.c
@@ -89,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);
@@ -113,15 +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:
@@ -162,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;
@@ -176,9 +181,10 @@ 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;
@@ -217,12 +223,12 @@ int ni_tio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
"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);
@@ -271,8 +277,16 @@ int ni_tio_cmdtest(struct comedi_device *dev,
/* 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);
@@ -450,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);
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 53613b385f3..4c1b9470647 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -131,34 +131,32 @@
#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 */
@@ -331,213 +329,388 @@ static const struct comedi_lrange range_a821pgh_ai = {
};
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);
- }
- dev_dbg(dev->class_dev, "A/D insn read timeout\n");
- outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE);
- return -ETIME;
+ 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);
-conv_finish:
- data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO);
+ 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;
}
- dev_dbg(dev->class_dev, "A/D insn read timeout\n");
- 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;
}
- outb(0, dev->iobase + PCL812_MODE);
- return n;
+ if (devpriv->dmabytestomove[1] > devpriv->hwdmasize) {
+ devpriv->dmabytestomove[1] = devpriv->hwdmasize;
+ 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);
}
-/*
-==============================================================================
-*/
-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)
{
@@ -545,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 */
@@ -585,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)
@@ -599,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)
@@ -615,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;
@@ -685,197 +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->read_subdev;
- 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 (err) {
+ 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;
+}
+
+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");
- pcl812_ai_cancel(dev, s);
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);
+ if (cmd->chanlist[s->async->cur_chan] != cmd->chanlist[next_chan])
+ pcl812_ai_set_chan_range(dev, cmd->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;
- }
- }
-
- 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->read_subdev;
- unsigned long dma_flags;
int len, bufptr;
unsigned short *ptr;
@@ -883,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;
@@ -979,204 +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));
+ }
- 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;
+ /* 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;
+
+ /* 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 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;
+ 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], interrupt_pcl812, 0,
+ ret = request_irq(it->options[1], pcl812_interrupt, 0,
dev->board_name, dev);
if (ret == 0)
dev->irq = it->options[1];
}
- 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) {
- dev_err(dev->class_dev,
- "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) {
dev_err(dev->class_dev,
- "unable to allocate DMA %u, FAIL!\n", dma);
- return -EBUSY; /* DMA isn't free */
- }
- devpriv->dma = dma;
- pages = 1; /* we want 8KB */
- devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[0]) {
- dev_err(dev->class_dev,
- "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]) {
- dev_err(dev->class_dev,
- "unable to allocate DMA buffer, FAIL!\n");
+ "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)
@@ -1184,146 +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->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;
- 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;
- }
- 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;
- }
- 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;
- }
- 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;
- }
- 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->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)
@@ -1342,33 +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->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->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:
@@ -1390,8 +1401,6 @@ no_dma:
break;
}
- devpriv->valid = 1;
-
pcl812_reset(dev);
return 0;
@@ -1403,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 e9d47045993..d9ca7fe16c9 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -44,40 +44,38 @@ Configuration Options:
#include "comedi_fc.h"
#include "8253.h"
-/* boards constants */
-/* IO space len */
-#define PCLx1x_RANGE 16
-
-/* 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
@@ -95,314 +93,282 @@ static const struct comedi_lrange range_pcl816 = {
};
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_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 */
+ 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;
-
- /* 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->read_subdev;
- 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);
- comedi_buf_put(s->async, (hi << 8) | low);
+ pcl816_ai_set_chan_scan(dev, first_chan, last_chan);
+}
- outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
+static void pcl816_ai_clear_eoc(struct comedi_device *dev)
+{
+ /* writing any value clears the interrupt request */
+ outb(0, dev->iobase + PCL816_CLRINT_REG);
+}
- if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len)
- devpriv->ai_act_chanlist_pos = 0;
+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);
+}
+
+static unsigned int pcl816_ai_get_sample(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ unsigned int val;
+
+ val = inb(dev->iobase + PCL816_AI_MSB_REG) << 8;
+ val |= inb(dev->iobase + PCL816_AI_LSB_REG);
+
+ 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 pcl816_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
- int len, bufptr, this_dma_buf;
- unsigned long dma_flags;
+ struct pcl816_private *devpriv = dev->private;
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;
-
- 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);
- }
+ pcl816_ai_clear_eoc(dev);
- outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */
- if (!dev->irq || !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;
+ 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;
+ unsigned int arg;
/* Step 1 : check if triggers are trivially valid */
@@ -432,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);
@@ -450,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)
@@ -477,120 +440,40 @@ 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;
+ devpriv->ai_cmd_canceled = 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;
- }
-
- 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);
+ pcl816_ai_setup_dma(dev, s);
- /* write irq and DMA to card */
- outb(dmairq, dev->iobase + PCL816_STATUS);
- break;
+ pcl816_start_pacer(dev, true);
- default:
- devpriv->int816_mode = INT_TYPE_AI3_DMA;
-
- /* 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);
return 0;
}
@@ -601,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++) {
@@ -618,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 */
@@ -634,134 +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;
- 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;
- }
- }
- 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) {
- dev_dbg(dev->class_dev, "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,
@@ -818,180 +598,181 @@ 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;
- devpriv->ai_act_chanlist_len = seglen;
- devpriv->ai_act_chanlist_pos = 0;
+ outb(PCL816_CTRL_SOFT_TRIG, dev->iobase + PCL816_CTRL_REG);
- 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);
+ 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);
- udelay(1);
- /* select channel interval to scan */
- outb(devpriv->ai_act_chanlist[0] |
- (devpriv->ai_act_chanlist[seglen - 1] << 4),
- dev->iobase + PCL816_MUX);
+ return ret ? ret : insn->n;
+}
+
+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;
+}
+
+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);
+ }
+
+ 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 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)) {
- dev_err(dev->class_dev, "I can't detect board. FAIL!\n");
- return -EIO;
- }
+ int ret;
+ int i;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
return -ENOMEM;
- if ((1 << it->options[1]) & board->IRQbits) {
- ret = request_irq(it->options[1], interrupt_pcl816, 0,
+ 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];
}
- 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 (!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 (dma < 1)
- goto no_dma; /* DMA disabled */
-
- if (((1 << dma) & board->DMAbits) == 0) {
- dev_err(dev->class_dev,
- "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) {
dev_err(dev->class_dev,
- "unable to allocate DMA %u, FAIL!\n", dma);
- return -EBUSY; /* DMA isn't free */
+ "unable to request DMA channel %d\n",
+ it->options[2]);
+ return -EBUSY;
}
+ devpriv->dma = it->options[2];
- devpriv->dma = dma;
- pages = 2; /* we need 16KB */
- devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages);
+ devpriv->dmapages = 2; /* we need 16KB */
+ devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
- if (!devpriv->dmabuf[0]) {
- dev_err(dev->class_dev,
- "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;
+ for (i = 0; i < 2; i++) {
+ unsigned long dmabuf;
- devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[1]) {
- dev_err(dev->class_dev,
- "unable to allocate DMA buffer, FAIL!\n");
- return -EBUSY;
+ dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
+ if (!dmabuf)
+ return -ENOMEM;
+
+ devpriv->dmabuf[i] = dmabuf;
+ devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
}
- devpriv->dmapages[1] = pages;
- devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
- devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
}
-no_dma:
-
-/* 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;
-*/
-
- 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;
- s->subdev_flags = SDF_CMD_READ | SDF_DIFF;
- s->n_chan = board->n_aichan;
- s->maxdata = board->ai_maxdata;
- s->range_table = board->ai_range_type;
- s->insn_read = pcl816_ai_insn_read;
- if (dev->irq) {
- dev->read_subdev = s;
- 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;
- }
- } else {
- s->type = COMEDI_SUBD_UNUSED;
+ 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_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
+ /* 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;
+
pcl816_reset(dev);
return 0;
@@ -1007,34 +788,13 @@ static void pcl816_detach(struct comedi_device *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 fa1758ad49d..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,19 +162,7 @@ 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
@@ -262,630 +240,439 @@ static const struct comedi_lrange range718_unipolar1 = {
};
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_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;
- 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->read_subdev;
- unsigned char low;
- int timeout = 50; /* wait max 50us */
+ unsigned int status;
- 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;
+ 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 */
+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;
- if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
+ expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos];
+ if (chan != expected_chan) {
dev_dbg(dev->class_dev,
- "A/D mode1/3 IRQ - channel dropout %x!=%x !\n",
- (low & 0xf),
- devpriv->act_chanlist[devpriv->act_chanlist_pos]);
- pcl818_ai_cancel(dev, s);
+ "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) {
+ 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->read_subdev;
- 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);
- }
+ 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! */
- dev_dbg(dev->class_dev,
- "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;
- }
+ val = ptr[bufptr++];
+ chan = val & 0xf;
+ val = (val >> 4) & s->maxdata;
- comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */
+ if (pcl818_ai_dropout(dev, s, chan))
+ break;
- devpriv->act_chanlist_pos++;
- if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
- devpriv->act_chanlist_pos = 0;
+ comedi_buf_put(s, val);
- s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
- s->async->cur_chan = 0;
- devpriv->ai_act_scan--;
- }
-
- 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;
}
-/*
-==============================================================================
- 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->read_subdev;
+ 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! */
- dev_dbg(dev->class_dev,
- "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;
}
- 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.
- */
- devpriv->ai_act_scan = 0;
- devpriv->neverending_ai = 0;
- pcl818_ai_cancel(dev, dev->read_subdev);
- }
-
- 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 (!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;
-
- 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;
-
- 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 */
- 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);
-
- 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)
@@ -941,52 +728,20 @@ static int check_channel_list(struct comedi_device *dev,
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 */
@@ -1033,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)
@@ -1057,152 +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);
- 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;
+ ctrl |= PCL818_CTRL_EXT_TRIG;
- 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);
- return retval;
- }
- if (cmd->convert_src == TRIG_EXT) { /* mode 3 */
- return pcl818_ai_cmd_mode(3, dev, s);
- }
+ 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);
+
+ if (cmd->convert_src == TRIG_TIMER)
+ pcl818_start_pacer(dev, true);
- return -1;
+ 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) {
- 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);
+ }
+
+ 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;
-end:
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;
+ }
}
}
@@ -1210,154 +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;
- 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;
- }
-
- if ((1 << it->options[1]) & board->IRQbits) {
- ret = request_irq(it->options[1], interrupt_pcl818, 0,
+ /* 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];
}
- 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 (!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 (dma < 1)
- goto no_dma; /* DMA disabled */
- if (((1 << dma) & board->DMAbits) == 0) {
+ /* 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,
- "DMA is out of allowed range, FAIL!\n");
- return -EINVAL; /* Bad DMA */
- }
- 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;
- devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[1])
+ "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];
+
+ devpriv->dmapages = 2; /* we need 16KB */
+ devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
-no_dma:
+ 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, 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;
- 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;
- } else {
- s->n_chan = board->n_aichan_diff;
- s->subdev_flags |= SDF_DIFF;
- }
- s->maxdata = board->ai_maxdata;
- s->range_table = board->ai_range_type;
- 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 = ai_cmd;
- s->cancel = pcl818_ai_cancel;
- }
- 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->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;
@@ -1369,31 +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->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->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))
@@ -1424,38 +1235,13 @@ static void pcl818_detach(struct comedi_device *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 f4a49bd649f..53e73737a90 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -225,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 c388f7f3222..fed7e77e030 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -192,7 +192,6 @@ struct pcmmio_private {
unsigned int enabled_mask;
unsigned int stop_count;
unsigned int active:1;
- unsigned int continuous:1;
unsigned int ao_readback[8];
};
@@ -339,8 +338,8 @@ static void pcmmio_handle_dio_intr(struct comedi_device *dev,
unsigned int triggered)
{
struct pcmmio_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned int oldevents = s->async->events;
- unsigned int len = s->async->cmd.chanlist_len;
unsigned int val = 0;
unsigned long flags;
int i;
@@ -353,16 +352,16 @@ static void pcmmio_handle_dio_intr(struct comedi_device *dev,
if (!(triggered & devpriv->enabled_mask))
goto done;
- for (i = 0; i < len; i++) {
- unsigned int chan = CR_CHAN(s->async->cmd.chanlist[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!! */
@@ -371,15 +370,12 @@ static void pcmmio_handle_dio_intr(struct comedi_device *dev,
}
/* Check for end of acquisition. */
- if (!devpriv->continuous) {
- /* stop_src == TRIG_COUNT */
- if (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);
- }
+ 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);
}
}
@@ -421,7 +417,7 @@ static int pcmmio_start_intr(struct comedi_device *dev,
unsigned int pol_bits = 0;
int i;
- if (!devpriv->continuous && devpriv->stop_count == 0) {
+ if (cmd->stop_src == TRIG_COUNT && devpriv->stop_count == 0) {
/* An empty acquisition! */
s->async->events |= COMEDI_CB_EOA;
devpriv->active = 0;
@@ -464,18 +460,16 @@ static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
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(&devpriv->spinlock, flags);
@@ -504,28 +498,17 @@ static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->active = 1;
/* Set up end of acquisition. */
- switch (cmd->stop_src) {
- case TRIG_COUNT:
- devpriv->continuous = 0;
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->stop_count = cmd->stop_arg;
- break;
- default:
- /* TRIG_NONE */
- devpriv->continuous = 1;
+ else /* TRIG_NONE */
devpriv->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 = pcmmio_inttrig_start_intr;
- break;
- default:
- /* TRIG_NOW */
+ else /* TRIG_NOW */
event = pcmmio_start_intr(dev, s);
- break;
- }
+
spin_unlock_irqrestore(&devpriv->spinlock, flags);
if (event)
@@ -589,16 +572,17 @@ static int pcmmio_cmdtest(struct comedi_device *dev,
return 0;
}
-static int pcmmio_ai_wait_for_eoc(unsigned long iobase, unsigned int timeout)
+static int pcmmio_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
unsigned char status;
- while (timeout--) {
- status = inb(iobase + PCMMIO_AI_STATUS_REG);
- if (status & PCMMIO_AI_STATUS_DATA_READY)
- return 0;
- }
- return -ETIME;
+ status = inb(dev->iobase + PCMMIO_AI_STATUS_REG);
+ if (status & PCMMIO_AI_STATUS_DATA_READY)
+ return 0;
+ return -EBUSY;
}
static int pcmmio_ai_insn_read(struct comedi_device *dev,
@@ -643,7 +627,8 @@ static int pcmmio_ai_insn_read(struct comedi_device *dev,
cmd |= PCMMIO_AI_CMD_RANGE(range);
outb(cmd, iobase + PCMMIO_AI_CMD_REG);
- ret = pcmmio_ai_wait_for_eoc(iobase, 100000);
+
+ ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0);
if (ret)
return ret;
@@ -652,7 +637,8 @@ static int pcmmio_ai_insn_read(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
outb(cmd, iobase + PCMMIO_AI_CMD_REG);
- ret = pcmmio_ai_wait_for_eoc(iobase, 100000);
+
+ ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0);
if (ret)
return ret;
@@ -684,16 +670,17 @@ static int pcmmio_ao_insn_read(struct comedi_device *dev,
return insn->n;
}
-static int pcmmio_ao_wait_for_eoc(unsigned long iobase, unsigned int timeout)
+static int pcmmio_ao_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
unsigned char status;
- while (timeout--) {
- status = inb(iobase + PCMMIO_AO_STATUS_REG);
- if (status & PCMMIO_AO_STATUS_DATA_READY)
- return 0;
- }
- return -ETIME;
+ 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,
@@ -726,7 +713,8 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev,
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 = pcmmio_ao_wait_for_eoc(iobase, 100000);
+
+ ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0);
if (ret)
return ret;
@@ -738,7 +726,8 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev,
outb((val >> 8) & 0xff, iobase + PCMMIO_AO_MSB_REG);
outb(cmd | PCMMIO_AO_CMD_WR_CODE_UPDATE,
iobase + PCMMIO_AO_CMD_REG);
- ret = pcmmio_ao_wait_for_eoc(iobase, 100000);
+
+ ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index a8f390f7a87..62914bb342d 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -317,7 +317,7 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev,
struct pcmuio_private *devpriv = dev->private;
int asic = pcmuio_subdevice_to_asic(s);
struct pcmuio_asic *chip = &devpriv->asics[asic];
- unsigned int len = s->async->cmd.chanlist_len;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned oldevents = s->async->events;
unsigned int val = 0;
unsigned long flags;
@@ -331,15 +331,15 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev,
if (!(triggered & chip->enabled_mask))
goto done;
- for (i = 0; i < len; i++) {
- unsigned int chan = CR_CHAN(s->async->cmd.chanlist[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!! */
@@ -460,20 +460,18 @@ static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
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_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(&chip->spinlock, flags);
@@ -518,15 +516,11 @@ static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
/* 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(&chip->spinlock, flags);
if (event)
diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h
index 55e3c2e2bc5..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;
};
/**********************************************************************
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 0f026afde9b..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
======================================================================*/
@@ -562,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);
@@ -593,14 +585,9 @@ 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);
@@ -642,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 */
@@ -671,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 */
@@ -792,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 */
@@ -891,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 {
@@ -904,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);
}
}
@@ -1116,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)
@@ -1127,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 +
@@ -1136,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 */
@@ -1157,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 */
@@ -1382,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;
}
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 19da1dbea49..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,
@@ -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);
}
@@ -1846,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)
@@ -1856,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;
/*
@@ -1897,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) {
@@ -1934,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. */
@@ -1965,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 */
@@ -1985,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;
@@ -2093,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 */
@@ -2116,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 */
@@ -2175,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 */
@@ -2203,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)
@@ -2252,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);
}
}
@@ -2299,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;
@@ -2307,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;
@@ -2543,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,
@@ -2582,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
@@ -2592,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;
}
/*
@@ -2749,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
@@ -2763,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);
@@ -2780,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,
@@ -2900,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;
}
diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c
index 77e2059ff62..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;
}
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/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 71db683098d..5f65e4213c6 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -202,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 */
@@ -266,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) {
@@ -349,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? */
@@ -363,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 */
@@ -373,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);
@@ -414,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;
@@ -463,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) {
@@ -478,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 |
@@ -493,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;
@@ -692,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;
@@ -777,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;
}
@@ -913,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;
@@ -1030,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);
@@ -1040,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) */
@@ -1077,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 5f85c55c110..85f9dcf5940 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -154,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 */
@@ -239,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;
@@ -285,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)) {
@@ -372,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);
@@ -398,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;
@@ -424,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:
@@ -454,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);
@@ -514,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;
@@ -822,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 */
@@ -848,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 88c60b6020c..ccc3ef7ba55 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -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;
}
@@ -856,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);
@@ -985,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;
}
@@ -1004,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;
@@ -1027,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;
}
diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
index 7dc5a18e69d..8777f958c04 100644
--- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
+++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
@@ -41,7 +41,8 @@ struct comedi_device *comedi_open(const char *filename)
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;
diff --git a/drivers/staging/comedi/proc.c b/drivers/staging/comedi/proc.c
index da6bc5855eb..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,11 +33,8 @@ 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_get_from_minor(i);
diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c
index 46b3da68638..b6849545b81 100644
--- a/drivers/staging/comedi/range.c
+++ b/drivers/staging/comedi/range.c
@@ -143,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;
}