aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi')
-rw-r--r--drivers/staging/comedi/Kconfig77
-rw-r--r--drivers/staging/comedi/comedi.h32
-rw-r--r--drivers/staging/comedi/comedi_buf.c66
-rw-r--r--drivers/staging/comedi/comedi_fops.c30
-rw-r--r--drivers/staging/comedi/comedi_pci.c24
-rw-r--r--drivers/staging/comedi/comedidev.h27
-rw-r--r--drivers/staging/comedi/drivers.c137
-rw-r--r--drivers/staging/comedi/drivers/8253.h8
-rw-r--r--drivers/staging/comedi/drivers/8255.c198
-rw-r--r--drivers/staging/comedi/drivers/8255.h31
-rw-r--r--drivers/staging/comedi/drivers/8255_pci.c38
-rw-r--r--drivers/staging/comedi/drivers/Makefile6
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.c20
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.h3
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_eeprom.c12
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c2
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c453
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c181
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c383
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1032.c12
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1516.c4
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1564.c133
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_16xx.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2032.c48
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2200.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3120.c54
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3501.c23
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3xxx.c37
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c40
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7x3x.c2
-rw-r--r--drivers/staging/comedi/drivers/adl_pci8164.c2
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c32
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c2084
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c22
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c2
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1724.c2
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c23
-rw-r--r--drivers/staging/comedi/drivers/aio_aio12_8.c52
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.c121
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.h34
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_common.c478
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_pci.c167
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236_common.c14
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c755
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c1224
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci236.c9
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci263.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c44
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c76
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c221
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c29
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c78
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c62
-rw-r--r--drivers/staging/comedi/drivers/comedi_fc.c132
-rw-r--r--drivers/staging/comedi/drivers/comedi_fc.h40
-rw-r--r--drivers/staging/comedi/drivers/comedi_parport.c8
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c10
-rw-r--r--drivers/staging/comedi/drivers/contec_pci_dio.c2
-rw-r--r--drivers/staging/comedi/drivers/dac02.c33
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c76
-rw-r--r--drivers/staging/comedi/drivers/das08.c85
-rw-r--r--drivers/staging/comedi/drivers/das08.h1
-rw-r--r--drivers/staging/comedi/drivers/das08_isa.c2
-rw-r--r--drivers/staging/comedi/drivers/das08_pci.c2
-rw-r--r--drivers/staging/comedi/drivers/das16.c34
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c10
-rw-r--r--drivers/staging/comedi/drivers/das1800.c28
-rw-r--r--drivers/staging/comedi/drivers/das6402.c16
-rw-r--r--drivers/staging/comedi/drivers/das800.c10
-rw-r--r--drivers/staging/comedi/drivers/dmm32at.c69
-rw-r--r--drivers/staging/comedi/drivers/dt2801.c38
-rw-r--r--drivers/staging/comedi/drivers/dt2811.c48
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c57
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c70
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c27
-rw-r--r--drivers/staging/comedi/drivers/dyna_pci10xx.c2
-rw-r--r--drivers/staging/comedi/drivers/fl512.c35
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c51
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c67
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c39
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c2
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c2
-rw-r--r--drivers/staging/comedi/drivers/me4000.c101
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c36
-rw-r--r--drivers/staging/comedi/drivers/mf6x4.c46
-rw-r--r--drivers/staging/comedi/drivers/multiq3.c46
-rw-r--r--drivers/staging/comedi/drivers/ni_6527.c11
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c15
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c8
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c66
-rw-r--r--drivers/staging/comedi/drivers/ni_at_a2150.c24
-rw-r--r--drivers/staging/comedi/drivers/ni_at_ao.c37
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio16d.c72
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c1378
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_common.c1387
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_isadma.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_pci.c11
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c114
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c17
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_stc.h1
-rw-r--r--drivers/staging/comedi/drivers/ni_tiocmd.c7
-rw-r--r--drivers/staging/comedi/drivers/ni_usb6501.c621
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c42
-rw-r--r--drivers/staging/comedi/drivers/pcl724.c12
-rw-r--r--drivers/staging/comedi/drivers/pcl726.c43
-rw-r--r--drivers/staging/comedi/drivers/pcl730.c2
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c46
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c2
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c41
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c27
-rw-r--r--drivers/staging/comedi/drivers/pcmad.c2
-rw-r--r--drivers/staging/comedi/drivers/pcmda12.c16
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c72
-rw-r--r--drivers/staging/comedi/drivers/pcmuio.c58
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c11
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c66
-rw-r--r--drivers/staging/comedi/drivers/rti800.c34
-rw-r--r--drivers/staging/comedi/drivers/rti802.c29
-rw-r--r--drivers/staging/comedi/drivers/s526.c43
-rw-r--r--drivers/staging/comedi/drivers/s626.c136
-rw-r--r--drivers/staging/comedi/drivers/skel.c726
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c53
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c54
-rw-r--r--drivers/staging/comedi/drivers/vmk80xx.c2
128 files changed, 5981 insertions, 8158 deletions
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 36f2c7159250..152f4c12ea43 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -42,24 +42,20 @@ menuconfig COMEDI_MISC_DRIVERS
if COMEDI_MISC_DRIVERS
-config COMEDI_KCOMEDILIB
- tristate "Comedi kcomedilib"
- ---help---
- Build the kcomedilib
-
config COMEDI_BOND
- tristate "Device bonding support"
- depends on COMEDI_KCOMEDILIB
+ tristate "Comedi device bonding support"
+ select COMEDI_KCOMEDILIB
---help---
Enable support for a driver to 'bond' (merge) multiple subdevices
from multiple devices together as one.
+ Currently, it only handles digital I/O subdevices.
+
To compile this driver as a module, choose M here: the module will be
called comedi_bond.
config COMEDI_TEST
tristate "Fake waveform generator support"
- select COMEDI_FC
---help---
Enable support for the fake waveform generator.
This driver is mainly for testing purposes, but can also be used to
@@ -88,14 +84,6 @@ config COMEDI_SERIAL2002
To compile this driver as a module, choose M here: the module will be
called serial2002.
-config COMEDI_SKEL
- tristate "Comedi skeleton driver"
- ---help---
- Build the Skeleton driver, an example for driver writers
-
- To compile this driver as a module, choose M here: the module will be
- called skel.
-
config COMEDI_SSV_DNP
tristate "SSV Embedded Systems DIL/Net-PC support"
depends on X86_32 || COMPILE_TEST
@@ -181,7 +169,6 @@ 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,
@@ -193,7 +180,6 @@ 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
@@ -203,7 +189,6 @@ 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
@@ -275,7 +260,6 @@ config COMEDI_DAC02
config COMEDI_DAS16M1
tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support"
select COMEDI_8255
- select COMEDI_FC
---help---
Enable support for Measurement Computing CIO-DAS16/M1 ISA cards.
@@ -299,7 +283,6 @@ config COMEDI_DAS16
tristate "DAS-16 compatible ISA and PC/104 card support"
depends on ISA_DMA_API
select COMEDI_8255
- select COMEDI_FC
---help---
Enable support for Keithley Metrabyte/ComputerBoards DAS16
and compatible ISA and PC/104 cards:
@@ -315,7 +298,6 @@ config COMEDI_DAS16
config COMEDI_DAS800
tristate "DAS800 and compatible ISA card support"
- select COMEDI_FC
---help---
Enable support for Keithley Metrabyte DAS800 and compatible ISA cards
Keithley Metrabyte DAS-800, DAS-801, DAS-802
@@ -328,7 +310,6 @@ config COMEDI_DAS800
config COMEDI_DAS1800
tristate "DAS1800 and compatible ISA card support"
depends on VIRT_TO_BUS && ISA_DMA_API
- select COMEDI_FC
---help---
Enable support for DAS1800 and compatible ISA cards
Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO,
@@ -391,7 +372,6 @@ config COMEDI_DT2817
config COMEDI_DT282X
tristate "Data Translation DT2821 series and DT-EZ ISA card support"
- select COMEDI_FC
depends on VIRT_TO_BUS && ISA_DMA_API
---help---
Enable support for Data Translation DT2821 series including DT-EZ
@@ -446,6 +426,7 @@ config COMEDI_AIO_IIRO_16
config COMEDI_II_PCI20KC
tristate "Intelligent Instruments PCI-20001C carrier support"
+ depends on HAS_IOMEM
---help---
Enable support for Intelligent Instruments PCI-20001C carrier
PCI-20001, PCI-20006 and PCI-20341
@@ -480,7 +461,6 @@ config COMEDI_ADQ12B
config COMEDI_NI_AT_A2150
tristate "NI AT-A2150 ISA card support"
- select COMEDI_FC
depends on VIRT_TO_BUS && ISA_DMA_API
---help---
Enable support for National Instruments AT-A2150 cards
@@ -500,7 +480,6 @@ config COMEDI_NI_ATMIO
tristate "NI AT-MIO E series ISA-PNP card support"
select COMEDI_8255
select COMEDI_NI_TIO
- select COMEDI_FC
---help---
Enable support for National Instruments AT-MIO E series cards
National Instruments AT-MIO-16E-1 (ni_atmio),
@@ -688,8 +667,7 @@ config COMEDI_ADDI_APCI_2200
config COMEDI_ADDI_APCI_3120
tristate "ADDI-DATA APCI_3120/3001 support"
- depends on VIRT_TO_BUS
- select COMEDI_FC
+ depends on HAS_DMA
---help---
Enable support for ADDI-DATA APCI_3120/3001 cards
@@ -741,7 +719,6 @@ config COMEDI_ADL_PCI8164
config COMEDI_ADL_PCI9111
tristate "ADLink PCI-9111HR support"
- select COMEDI_FC
---help---
Enable support for ADlink PCI9111 cards
@@ -750,7 +727,7 @@ config COMEDI_ADL_PCI9111
config COMEDI_ADL_PCI9118
tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support"
- select COMEDI_FC
+ depends on HAS_DMA
depends on VIRT_TO_BUS
---help---
Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards
@@ -760,7 +737,6 @@ 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
@@ -828,7 +804,6 @@ config COMEDI_AMPLC_PC263_PCI
config COMEDI_AMPLC_PCI224
tristate "Amplicon PCI224 and PCI234 support"
- select COMEDI_FC
---help---
Enable support for Amplicon PCI224 and PCI234 AO boards
@@ -864,7 +839,6 @@ config COMEDI_DAS08_PCI
config COMEDI_DT3000
tristate "Data Translation DT3000 series support"
- select COMEDI_FC
---help---
Enable support for Data Translation DT3000 series
DT3001, DT3001-PGL, DT3002, DT3003, DT3003-PGL, DT3004, DT3005 and
@@ -884,7 +858,6 @@ config COMEDI_DYNA_PCI10XX
config COMEDI_GSC_HPDI
tristate "General Standards PCI-HPDI32 / PMC-HPDI32 support"
- select COMEDI_FC
---help---
Enable support for General Standards Corporation high speed parallel
digital interface rs485 boards PCI-HPDI32 and PMC-HPDI32.
@@ -935,7 +908,6 @@ config COMEDI_KE_COUNTER
config COMEDI_CB_PCIDAS64
tristate "MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 support"
select COMEDI_8255
- select COMEDI_FC
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DAS 64xx,
60xx, and 4020 series with the PLX 9080 PCI controller
@@ -946,7 +918,6 @@ config COMEDI_CB_PCIDAS64
config COMEDI_CB_PCIDAS
tristate "MeasurementComputing PCI-DAS support"
select COMEDI_8255
- select COMEDI_FC
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DAS with
AMCC S5933 PCIcontroller: PCI-DAS1602/16, PCI-DAS1602/16jr,
@@ -1069,7 +1040,6 @@ config COMEDI_NI_PCIMIO
depends on HAS_DMA
select COMEDI_NI_TIOCMD
select COMEDI_8255
- select COMEDI_FC
---help---
Enable support for National Instruments PCI-MIO-E series and M series
(all boards): PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1,
@@ -1095,7 +1065,6 @@ config COMEDI_RTD520
config COMEDI_S626
tristate "Sensoray 626 support"
- select COMEDI_FC
---help---
Enable support for Sensoray 626
@@ -1104,7 +1073,6 @@ config COMEDI_S626
config COMEDI_MITE
depends on HAS_DMA
- select COMEDI_FC
tristate
config COMEDI_NI_TIOCMD
@@ -1172,7 +1140,6 @@ config COMEDI_NI_MIO_CS
tristate "NI DAQCard E series PCMCIA support"
select COMEDI_NI_TIO
select COMEDI_8255
- select COMEDI_FC
---help---
Enable support for the National Instruments PCMCIA DAQCard E series
DAQCard-ai-16xe-50, DAQCard-ai-16e-4, DAQCard-6062E, DAQCard-6024E
@@ -1183,7 +1150,6 @@ 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
@@ -1209,6 +1175,17 @@ config COMEDI_DT9812
To compile this driver as a module, choose M here: the module will be
called dt9812.
+config COMEDI_NI_USB6501
+ tristate "NI USB-6501 support"
+ ---help---
+ Enable support for the National Instruments USB-6501 module.
+
+ The NI USB-6501 is a Full-Speed USB 2.0 (12 Mbit/s) device that
+ provides 24 digital I/O lines channels and one 32-bit counter.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ni_usb6501.
+
config COMEDI_USBDUX
tristate "ITL USB-DUX-D support"
---help---
@@ -1219,7 +1196,6 @@ config COMEDI_USBDUX
config COMEDI_USBDUXFAST
tristate "ITL USB-DUXfast support"
- select COMEDI_FC
---help---
Enable support for the Incite Technology Ltd USB-DUXfast Board
@@ -1228,7 +1204,6 @@ config COMEDI_USBDUXFAST
config COMEDI_USBDUXSIGMA
tristate "ITL USB-DUXsigma support"
- select COMEDI_FC
---help---
Enable support for the Incite Technology Ltd USB-DUXsigma Board
@@ -1261,8 +1236,19 @@ config COMEDI_8255
To compile this driver as a module, choose M here: the module will be
called 8255.
-config COMEDI_FC
- tristate
+config COMEDI_KCOMEDILIB
+ tristate "Comedi kcomedilib"
+ ---help---
+ Build the kcomedilib.
+
+ This is a kernel module used to open and manipulate Comedi devices
+ from within kernel code. It is currently only used by the
+ comedi_bond driver, and its functionality has been stripped down to
+ the needs of that driver, so is currently not very useful for
+ anything else.
+
+ To compile kcomedilib as a module, choose M here: the module will be
+ called kcomedilib.
config COMEDI_AMPLC_DIO200
tristate
@@ -1278,7 +1264,6 @@ config COMEDI_DAS08
config COMEDI_NI_LABPC
tristate
select COMEDI_8255
- select COMEDI_FC
config COMEDI_NI_LABPC_ISADMA
tristate
diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h
index 217baf812f87..c8c99e65423b 100644
--- a/drivers/staging/comedi/comedi.h
+++ b/drivers/staging/comedi/comedi.h
@@ -123,38 +123,48 @@
/* trigger flags */
/* These flags are used in comedi_trig structures */
-#define TRIG_BOGUS 0x0001 /* do the motions */
#define TRIG_DITHER 0x0002 /* enable dithering */
#define TRIG_DEGLITCH 0x0004 /* enable deglitching */
- /*#define TRIG_RT 0x0008 *//* perform op in real time */
#define TRIG_CONFIG 0x0010 /* perform configuration, not triggering */
-#define TRIG_WAKE_EOS 0x0020 /* wake up on end-of-scan events */
- /*#define TRIG_WRITE 0x0040*//* write to bidirectional devices */
/* command flags */
/* These flags are used in comedi_cmd structures */
+#define CMDF_BOGUS 0x00000001 /* do the motions */
+
/* try to use a real-time interrupt while performing command */
#define CMDF_PRIORITY 0x00000008
-#define TRIG_RT CMDF_PRIORITY /* compatibility definition */
+/* wake up on end-of-scan events */
+#define CMDF_WAKE_EOS 0x00000020
#define CMDF_WRITE 0x00000040
-#define TRIG_WRITE CMDF_WRITE /* compatibility definition */
#define CMDF_RAWDATA 0x00000080
+/* timer rounding definitions */
+#define CMDF_ROUND_MASK 0x00030000
+#define CMDF_ROUND_NEAREST 0x00000000
+#define CMDF_ROUND_DOWN 0x00010000
+#define CMDF_ROUND_UP 0x00020000
+#define CMDF_ROUND_UP_NEXT 0x00030000
+
#define COMEDI_EV_START 0x00040000
#define COMEDI_EV_SCAN_BEGIN 0x00080000
#define COMEDI_EV_CONVERT 0x00100000
#define COMEDI_EV_SCAN_END 0x00200000
#define COMEDI_EV_STOP 0x00400000
-#define TRIG_ROUND_MASK 0x00030000
-#define TRIG_ROUND_NEAREST 0x00000000
-#define TRIG_ROUND_DOWN 0x00010000
-#define TRIG_ROUND_UP 0x00020000
-#define TRIG_ROUND_UP_NEXT 0x00030000
+/* compatibility definitions */
+#define TRIG_BOGUS CMDF_BOGUS
+#define TRIG_RT CMDF_PRIORITY
+#define TRIG_WAKE_EOS CMDF_WAKE_EOS
+#define TRIG_WRITE CMDF_WRITE
+#define TRIG_ROUND_MASK CMDF_ROUND_MASK
+#define TRIG_ROUND_NEAREST CMDF_ROUND_NEAREST
+#define TRIG_ROUND_DOWN CMDF_ROUND_DOWN
+#define TRIG_ROUND_UP CMDF_ROUND_UP
+#define TRIG_ROUND_UP_NEXT CMDF_ROUND_UP_NEXT
/* trigger sources */
diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c
index df4a9c4bca35..c60a45ad12b9 100644
--- a/drivers/staging/comedi/comedi_buf.c
+++ b/drivers/staging/comedi/comedi_buf.c
@@ -3,6 +3,7 @@
*
* COMEDI - Linux Control and Measurement Device Interface
* Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
+ * Copyright (C) 2002 Frank Mori Hess <fmhess@users.sourceforge.net>
*
* 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
@@ -509,3 +510,68 @@ void comedi_buf_memcpy_from(struct comedi_subdevice *s, unsigned int offset,
}
}
EXPORT_SYMBOL_GPL(comedi_buf_memcpy_from);
+
+/**
+ * comedi_write_array_to_buffer - write data to comedi buffer
+ * @s: comedi_subdevice struct
+ * @data: destination
+ * @num_bytes: number of bytes to write
+ *
+ * Writes up to num_bytes bytes of data to the comedi buffer associated with
+ * the subdevice, marks it as written and updates the acquisition scan
+ * progress.
+ *
+ * Returns the amount of data written in bytes.
+ */
+unsigned int comedi_write_array_to_buffer(struct comedi_subdevice *s,
+ const void *data,
+ unsigned int num_bytes)
+{
+ struct comedi_async *async = s->async;
+ unsigned int retval;
+
+ if (num_bytes == 0)
+ return 0;
+
+ retval = comedi_buf_write_alloc(s, num_bytes);
+ if (retval != num_bytes) {
+ dev_warn(s->device->class_dev, "buffer overrun\n");
+ async->events |= COMEDI_CB_OVERFLOW;
+ return 0;
+ }
+
+ comedi_buf_memcpy_to(s, 0, data, num_bytes);
+ comedi_buf_write_free(s, num_bytes);
+ comedi_inc_scan_progress(s, num_bytes);
+ async->events |= COMEDI_CB_BLOCK;
+
+ return num_bytes;
+}
+EXPORT_SYMBOL_GPL(comedi_write_array_to_buffer);
+
+/**
+ * comedi_read_array_from_buffer - read data from comedi buffer
+ * @s: comedi_subdevice struct
+ * @data: destination
+ * @num_bytes: number of bytes to read
+ *
+ * Reads up to num_bytes bytes of data from the comedi buffer associated with
+ * the subdevice, marks it as read and updates the acquisition scan progress.
+ *
+ * Returns the amount of data read in bytes.
+ */
+unsigned int comedi_read_array_from_buffer(struct comedi_subdevice *s,
+ void *data, unsigned int num_bytes)
+{
+ if (num_bytes == 0)
+ return 0;
+
+ 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);
+ comedi_inc_scan_progress(s, num_bytes);
+ s->async->events |= COMEDI_CB_BLOCK;
+
+ return num_bytes;
+}
+EXPORT_SYMBOL_GPL(comedi_read_array_from_buffer);
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 2182c7463cdb..9c32f0276009 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -1462,10 +1462,7 @@ static int __comedi_get_user_chanlist(struct comedi_device *dev,
unsigned int *chanlist;
int ret;
- /* user_chanlist could be NULL for do_cmdtest ioctls */
- if (!user_chanlist)
- return 0;
-
+ cmd->chanlist = NULL;
chanlist = memdup_user(user_chanlist,
cmd->chanlist_len * sizeof(unsigned int));
if (IS_ERR(chanlist))
@@ -1532,7 +1529,7 @@ static int do_cmd_ioctl(struct comedi_device *dev,
ret = s->do_cmdtest(dev, s, &async->cmd);
- if (async->cmd.flags & TRIG_BOGUS || ret) {
+ if (async->cmd.flags & CMDF_BOGUS || ret) {
dev_dbg(dev->class_dev, "test returned %d\n", ret);
cmd = async->cmd;
/* restore chanlist pointer before copying back */
@@ -1558,7 +1555,7 @@ static int do_cmd_ioctl(struct comedi_device *dev,
async->cb_mask =
COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
COMEDI_CB_OVERFLOW;
- if (async->cmd.flags & TRIG_WAKE_EOS)
+ if (async->cmd.flags & CMDF_WAKE_EOS)
async->cb_mask |= COMEDI_CB_EOS;
comedi_set_subdevice_runflags(s, SRF_ERROR | SRF_RUNNING, SRF_RUNNING);
@@ -1609,13 +1606,18 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
s = &dev->subdevices[cmd.subdev];
- /* load channel/gain list */
- ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd);
- if (ret)
- return ret;
+ /* user_chanlist can be NULL for COMEDI_CMDTEST ioctl */
+ if (user_chanlist) {
+ /* load channel/gain list */
+ ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd);
+ if (ret)
+ return ret;
+ }
ret = s->do_cmdtest(dev, s, &cmd);
+ kfree(cmd.chanlist); /* free kernel copy of user chanlist */
+
/* restore chanlist pointer before copying back */
cmd.chanlist = (unsigned int __force *)user_chanlist;
@@ -1642,7 +1644,7 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
*/
-static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
+static int do_lock_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
int ret = 0;
@@ -1679,7 +1681,7 @@ static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
This function isn't protected by the semaphore, since
we already own the lock.
*/
-static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
+static int do_unlock_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
struct comedi_subdevice *s;
@@ -1714,7 +1716,7 @@ static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
nothing
*/
-static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
+static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
struct comedi_subdevice *s;
@@ -1751,7 +1753,7 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
nothing
*/
-static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
+static int do_poll_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
struct comedi_subdevice *s;
diff --git a/drivers/staging/comedi/comedi_pci.c b/drivers/staging/comedi/comedi_pci.c
index abbc0e4f5c51..aa0795a2660e 100644
--- a/drivers/staging/comedi/comedi_pci.c
+++ b/drivers/staging/comedi/comedi_pci.c
@@ -17,6 +17,7 @@
*/
#include <linux/pci.h>
+#include <linux/interrupt.h>
#include "comedidev.h"
@@ -73,6 +74,29 @@ void comedi_pci_disable(struct comedi_device *dev)
EXPORT_SYMBOL_GPL(comedi_pci_disable);
/**
+ * comedi_pci_detach() - A generic (*detach) function for PCI drivers.
+ * @dev: comedi_device struct
+ */
+void comedi_pci_detach(struct comedi_device *dev)
+{
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+
+ if (!pcidev || !dev->ioenabled)
+ return;
+
+ if (dev->irq) {
+ free_irq(dev->irq, dev);
+ dev->irq = 0;
+ }
+ if (dev->mmio) {
+ iounmap(dev->mmio);
+ dev->mmio = NULL;
+ }
+ comedi_pci_disable(dev);
+}
+EXPORT_SYMBOL_GPL(comedi_pci_detach);
+
+/**
* comedi_pci_auto_config() - Configure/probe a comedi PCI driver.
* @pcidev: pci_dev struct
* @driver: comedi_driver struct
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index 58e58a32e93d..1b2bbd56f6ef 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -88,6 +88,8 @@ struct comedi_subdevice {
struct device *class_dev;
int minor;
+
+ unsigned int *readback;
};
struct comedi_buf_page {
@@ -267,11 +269,6 @@ struct comedi_device {
void (*close)(struct comedi_device *dev);
};
-static inline const void *comedi_board(const struct comedi_device *dev)
-{
- return dev->board_ptr;
-}
-
/*
* function prototypes
*/
@@ -429,6 +426,11 @@ 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_subdevice *s, unsigned int offset,
void *destination, unsigned int num_bytes);
+unsigned int comedi_write_array_to_buffer(struct comedi_subdevice *s,
+ const void *data,
+ unsigned int num_bytes);
+unsigned int comedi_read_array_from_buffer(struct comedi_subdevice *s,
+ void *data, unsigned int num_bytes);
/* drivers.c - general comedi driver functions */
@@ -440,14 +442,24 @@ int comedi_timeout(struct comedi_device *, struct comedi_subdevice *,
struct comedi_insn *, unsigned long context),
unsigned long context);
+unsigned int comedi_handle_events(struct comedi_device *dev,
+ struct comedi_subdevice *s);
+
int comedi_dio_insn_config(struct comedi_device *, struct comedi_subdevice *,
struct comedi_insn *, unsigned int *data,
unsigned int mask);
unsigned int comedi_dio_update_state(struct comedi_subdevice *,
unsigned int *data);
+unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s);
+void comedi_inc_scan_progress(struct comedi_subdevice *s,
+ unsigned int num_bytes);
void *comedi_alloc_devpriv(struct comedi_device *, size_t);
int comedi_alloc_subdevices(struct comedi_device *, int);
+int comedi_alloc_subdev_readback(struct comedi_subdevice *);
+
+int comedi_readback_insn_read(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *data);
int comedi_load_firmware(struct comedi_device *, struct device *,
const char *name,
@@ -503,6 +515,7 @@ struct pci_dev *comedi_to_pci_dev(struct comedi_device *);
int comedi_pci_enable(struct comedi_device *);
void comedi_pci_disable(struct comedi_device *);
+void comedi_pci_detach(struct comedi_device *);
int comedi_pci_auto_config(struct pci_dev *, struct comedi_driver *,
unsigned long context);
@@ -547,6 +560,10 @@ static inline void comedi_pci_disable(struct comedi_device *dev)
{
}
+static inline void comedi_pci_detach(struct comedi_device *dev)
+{
+}
+
#endif /* CONFIG_COMEDI_PCI_DRIVERS */
#ifdef CONFIG_COMEDI_PCMCIA_DRIVERS
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index 9ada130f2a76..3e5bccbc9c39 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -4,6 +4,7 @@
COMEDI - Linux Control and Measurement Device Interface
Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
+ Copyright (C) 2002 Frank Mori Hess <fmhess@users.sourceforge.net>
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
@@ -96,6 +97,22 @@ int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices)
}
EXPORT_SYMBOL_GPL(comedi_alloc_subdevices);
+/**
+ * comedi_alloc_subdev_readback() - Allocate memory for the subdevice readback.
+ * @s: comedi_subdevice struct
+ */
+int comedi_alloc_subdev_readback(struct comedi_subdevice *s)
+{
+ if (!s->n_chan)
+ return -EINVAL;
+
+ s->readback = kcalloc(s->n_chan, sizeof(*s->readback), GFP_KERNEL);
+ if (!s->readback)
+ return -ENOMEM;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(comedi_alloc_subdev_readback);
+
static void comedi_device_detach_cleanup(struct comedi_device *dev)
{
int i;
@@ -111,6 +128,7 @@ static void comedi_device_detach_cleanup(struct comedi_device *dev)
comedi_buf_alloc(dev, s, 0);
kfree(s->async);
}
+ kfree(s->readback);
}
kfree(dev->subdevices);
dev->subdevices = NULL;
@@ -157,6 +175,31 @@ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
}
/**
+ * comedi_readback_insn_read() - A generic (*insn_read) for subdevice readback.
+ * @dev: comedi_device struct
+ * @s: comedi_subdevice struct
+ * @insn: comedi_insn struct
+ * @data: pointer to return the readback data
+ */
+int comedi_readback_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ if (!s->readback)
+ return -EINVAL;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = s->readback[chan];
+
+ return insn->n;
+}
+EXPORT_SYMBOL_GPL(comedi_readback_insn_read);
+
+/**
* comedi_timeout() - busy-wait for a driver condition to occur.
* @dev: comedi_device struct
* @s: comedi_subdevice struct
@@ -248,6 +291,100 @@ unsigned int comedi_dio_update_state(struct comedi_subdevice *s,
}
EXPORT_SYMBOL_GPL(comedi_dio_update_state);
+/**
+ * comedi_bytes_per_scan - get length of asynchronous command "scan" in bytes
+ * @s: comedi_subdevice struct
+ *
+ * Determines the overall scan length according to the subdevice type and the
+ * number of channels in the scan.
+ *
+ * For digital input, output or input/output subdevices, samples for multiple
+ * channels are assumed to be packed into one or more unsigned short or
+ * unsigned int values according to the subdevice's SDF_LSAMPL flag. For other
+ * types of subdevice, samples are assumed to occupy a whole unsigned short or
+ * unsigned int according to the SDF_LSAMPL flag.
+ *
+ * Returns the overall scan length in bytes.
+ */
+unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s)
+{
+ 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(comedi_bytes_per_scan);
+
+/**
+ * comedi_inc_scan_progress - update scan progress in asynchronous command
+ * @s: comedi_subdevice struct
+ * @num_bytes: amount of data in bytes to increment scan progress
+ *
+ * Increments the scan progress by the number of bytes specified by num_bytes.
+ * If the scan progress reaches or exceeds the scan length in bytes, reduce
+ * it modulo the scan length in bytes and set the "end of scan" asynchronous
+ * event flag to be processed later.
+ */
+void comedi_inc_scan_progress(struct comedi_subdevice *s,
+ unsigned int num_bytes)
+{
+ struct comedi_async *async = s->async;
+ unsigned int scan_length = comedi_bytes_per_scan(s);
+
+ async->scan_progress += num_bytes;
+ if (async->scan_progress >= scan_length) {
+ async->scan_progress %= scan_length;
+ async->events |= COMEDI_CB_EOS;
+ }
+}
+EXPORT_SYMBOL_GPL(comedi_inc_scan_progress);
+
+/**
+ * comedi_handle_events - handle events and possibly stop acquisition
+ * @dev: comedi_device struct
+ * @s: comedi_subdevice struct
+ *
+ * Handles outstanding asynchronous acquisition event flags associated
+ * with the subdevice. Call the subdevice's "->cancel()" handler if the
+ * "end of acquisition", "error" or "overflow" event flags are set in order
+ * to stop the acquisition at the driver level.
+ *
+ * Calls comedi_event() to further process the event flags, which may mark
+ * the asynchronous command as no longer running, possibly terminated with
+ * an error, and may wake up tasks.
+ *
+ * Return a bit-mask of the handled events.
+ */
+unsigned int comedi_handle_events(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ unsigned int events = s->async->events;
+
+ if (events == 0)
+ return events;
+
+ if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW))
+ s->cancel(dev, s);
+
+ comedi_event(dev, s);
+
+ return events;
+}
+EXPORT_SYMBOL_GPL(comedi_handle_events);
+
static int insn_rw_emulate_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h
index f8e1ebad304d..9f4c1411719d 100644
--- a/drivers/staging/comedi/drivers/8253.h
+++ b/drivers/staging/comedi/drivers/8253.h
@@ -90,8 +90,8 @@ static inline void i8253_cascade_ns_to_timer(int i8253_osc_base,
}
}
- switch (flags & TRIG_ROUND_MASK) {
- case TRIG_ROUND_NEAREST:
+ switch (flags & CMDF_ROUND_MASK) {
+ case CMDF_ROUND_NEAREST:
default:
ns_high = div1_lub * div2_lub * i8253_osc_base;
ns_low = div1_glb * div2_glb * i8253_osc_base;
@@ -103,11 +103,11 @@ static inline void i8253_cascade_ns_to_timer(int i8253_osc_base,
div2 = div2_glb;
}
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
div1 = div1_lub;
div2 = div2_lub;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
div1 = div1_glb;
div2 = div2_glb;
break;
diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c
index a33a19622745..34d4d8b5f31e 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -79,49 +79,30 @@ I/O port base address can be found in the output of 'lspci -v'.
#include "comedi_fc.h"
#include "8255.h"
-#define _8255_SIZE 4
-
-#define _8255_DATA 0
-#define _8255_CR 3
-
-#define CR_C_LO_IO 0x01
-#define CR_B_IO 0x02
-#define CR_B_MODE 0x04
-#define CR_C_HI_IO 0x08
-#define CR_A_IO 0x10
-#define CR_A_MODE(a) ((a)<<5)
-#define CR_CW 0x80
-
struct subdev_8255_private {
- unsigned long iobase;
- int (*io)(int, int, int, unsigned long);
+ unsigned long regbase;
+ int (*io)(struct comedi_device *, int, int, int, unsigned long);
};
-static int subdev_8255_io(int dir, int port, int data, unsigned long iobase)
+static int subdev_8255_io(struct comedi_device *dev,
+ int dir, int port, int data, unsigned long regbase)
{
if (dir) {
- outb(data, iobase + port);
+ outb(data, dev->iobase + regbase + port);
return 0;
}
- return inb(iobase + port);
+ return inb(dev->iobase + regbase + port);
}
-void subdev_8255_interrupt(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static int subdev_8255_mmio(struct comedi_device *dev,
+ int dir, int port, int data, unsigned long regbase)
{
- struct subdev_8255_private *spriv = s->private;
- unsigned long iobase = spriv->iobase;
- unsigned short d;
-
- d = spriv->io(0, _8255_DATA, 0, iobase);
- d |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8);
-
- comedi_buf_put(s, d);
- s->async->events |= COMEDI_CB_EOS;
-
- comedi_event(dev, s);
+ if (dir) {
+ writeb(data, dev->mmio + regbase + port);
+ return 0;
+ }
+ return readb(dev->mmio + regbase + port);
}
-EXPORT_SYMBOL_GPL(subdev_8255_interrupt);
static int subdev_8255_insn(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -129,25 +110,26 @@ static int subdev_8255_insn(struct comedi_device *dev,
unsigned int *data)
{
struct subdev_8255_private *spriv = s->private;
- unsigned long iobase = spriv->iobase;
+ unsigned long regbase = spriv->regbase;
unsigned int mask;
unsigned int v;
mask = comedi_dio_update_state(s, data);
if (mask) {
if (mask & 0xff)
- spriv->io(1, _8255_DATA, s->state & 0xff, iobase);
+ spriv->io(dev, 1, I8255_DATA_A_REG,
+ s->state & 0xff, regbase);
if (mask & 0xff00)
- spriv->io(1, _8255_DATA + 1, (s->state >> 8) & 0xff,
- iobase);
+ spriv->io(dev, 1, I8255_DATA_B_REG,
+ (s->state >> 8) & 0xff, regbase);
if (mask & 0xff0000)
- spriv->io(1, _8255_DATA + 2, (s->state >> 16) & 0xff,
- iobase);
+ spriv->io(dev, 1, I8255_DATA_C_REG,
+ (s->state >> 16) & 0xff, regbase);
}
- v = spriv->io(0, _8255_DATA, 0, iobase);
- v |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8);
- v |= (spriv->io(0, _8255_DATA + 2, 0, iobase) << 16);
+ v = spriv->io(dev, 0, I8255_DATA_A_REG, 0, regbase);
+ v |= (spriv->io(dev, 0, I8255_DATA_B_REG, 0, regbase) << 8);
+ v |= (spriv->io(dev, 0, I8255_DATA_C_REG, 0, regbase) << 16);
data[1] = v;
@@ -158,21 +140,21 @@ static void subdev_8255_do_config(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct subdev_8255_private *spriv = s->private;
- unsigned long iobase = spriv->iobase;
+ unsigned long regbase = spriv->regbase;
int config;
- config = CR_CW;
+ config = I8255_CTRL_CW;
/* 1 in io_bits indicates output, 1 in config indicates input */
if (!(s->io_bits & 0x0000ff))
- config |= CR_A_IO;
+ config |= I8255_CTRL_A_IO;
if (!(s->io_bits & 0x00ff00))
- config |= CR_B_IO;
+ config |= I8255_CTRL_B_IO;
if (!(s->io_bits & 0x0f0000))
- config |= CR_C_LO_IO;
+ config |= I8255_CTRL_C_LO_IO;
if (!(s->io_bits & 0xf00000))
- config |= CR_C_HI_IO;
+ config |= I8255_CTRL_C_HI_IO;
- spriv->io(1, _8255_CR, config, iobase);
+ spriv->io(dev, 1, I8255_CTRL_REG, config, regbase);
}
static int subdev_8255_insn_config(struct comedi_device *dev,
@@ -202,67 +184,12 @@ static int subdev_8255_insn_config(struct comedi_device *dev,
return insn->n;
}
-static int subdev_8255_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
-{
- int err = 0;
-
- /* 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_FOLLOW);
- err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
- err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
-
- if (err)
- return 1;
-
- /* Step 2a : make sure trigger sources are unique */
- /* 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);
- 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, cmd->chanlist_len);
- err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
-
- if (err)
- return 3;
-
- /* step 4 */
-
- if (err)
- return 4;
-
- return 0;
-}
-
-static int subdev_8255_cmd(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- /* FIXME */
-
- return 0;
-}
-
-static int subdev_8255_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- /* FIXME */
-
- return 0;
-}
-
-int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
- int (*io)(int, int, int, unsigned long),
- unsigned long iobase)
+static int __subdev_8255_init(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ int (*io)(struct comedi_device *,
+ int, int, int, unsigned long),
+ unsigned long regbase,
+ bool is_mmio)
{
struct subdev_8255_private *spriv;
@@ -270,8 +197,13 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
if (!spriv)
return -ENOMEM;
- spriv->iobase = iobase;
- spriv->io = io ? io : subdev_8255_io;
+ if (io)
+ spriv->io = io;
+ else if (is_mmio)
+ spriv->io = subdev_8255_mmio;
+ else
+ spriv->io = subdev_8255_io;
+ spriv->regbase = regbase;
s->type = COMEDI_SUBD_DIO;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
@@ -285,27 +217,24 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
-EXPORT_SYMBOL_GPL(subdev_8255_init);
-int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
- int (*io)(int, int, int, unsigned long),
- unsigned long iobase)
+int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
+ int (*io)(struct comedi_device *,
+ int, int, int, unsigned long),
+ unsigned long regbase)
{
- int ret;
-
- ret = subdev_8255_init(dev, s, io, iobase);
- 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;
-
- return 0;
+ return __subdev_8255_init(dev, s, io, regbase, false);
}
-EXPORT_SYMBOL_GPL(subdev_8255_init_irq);
+EXPORT_SYMBOL_GPL(subdev_8255_init);
+int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s,
+ int (*io)(struct comedi_device *,
+ int, int, int, unsigned long),
+ unsigned long regbase)
+{
+ return __subdev_8255_init(dev, s, io, regbase, true);
+}
+EXPORT_SYMBOL_GPL(subdev_8255_mm_init);
/*
Start of the 8255 standalone device
@@ -316,8 +245,8 @@ static int dev_8255_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
- int ret;
unsigned long iobase;
+ int ret;
int i;
for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) {
@@ -338,7 +267,14 @@ static int dev_8255_attach(struct comedi_device *dev,
s = &dev->subdevices[i];
iobase = it->options[i];
- ret = __comedi_request_region(dev, iobase, _8255_SIZE);
+ /*
+ * __comedi_request_region() does not set dev->iobase.
+ *
+ * For 8255 devices that are manually attached using
+ * comedi_config, the 'iobase' is the actual I/O port
+ * base address of the chip.
+ */
+ ret = __comedi_request_region(dev, iobase, I8255_SIZE);
if (ret) {
s->type = COMEDI_SUBD_UNUSED;
} else {
@@ -361,7 +297,7 @@ static void dev_8255_detach(struct comedi_device *dev)
s = &dev->subdevices[i];
if (s->type != COMEDI_SUBD_UNUSED) {
spriv = s->private;
- release_region(spriv->iobase, _8255_SIZE);
+ release_region(spriv->regbase, I8255_SIZE);
}
}
}
diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h
index 795d232a6c02..5985c8e0330f 100644
--- a/drivers/staging/comedi/drivers/8255.h
+++ b/drivers/staging/comedi/drivers/8255.h
@@ -21,13 +21,28 @@
#include "../comedidev.h"
-int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
- 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),
- unsigned long iobase);
-void subdev_8255_interrupt(struct comedi_device *dev,
- struct comedi_subdevice *s);
+#define I8255_SIZE 0x04
+
+#define I8255_DATA_A_REG 0x00
+#define I8255_DATA_B_REG 0x01
+#define I8255_DATA_C_REG 0x02
+#define I8255_CTRL_REG 0x03
+#define I8255_CTRL_C_LO_IO (1 << 0)
+#define I8255_CTRL_B_IO (1 << 1)
+#define I8255_CTRL_B_MODE (1 << 2)
+#define I8255_CTRL_C_HI_IO (1 << 3)
+#define I8255_CTRL_A_IO (1 << 4)
+#define I8255_CTRL_A_MODE(x) ((x) << 5)
+#define I8255_CTRL_CW (1 << 7)
+
+int subdev_8255_init(struct comedi_device *, struct comedi_subdevice *,
+ int (*io)(struct comedi_device *,
+ int, int, int, unsigned long),
+ unsigned long regbase);
+
+int subdev_8255_mm_init(struct comedi_device *, struct comedi_subdevice *,
+ int (*io)(struct comedi_device *,
+ int, int, int, unsigned long),
+ unsigned long regbase);
#endif
diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c
index f21e6567ac2f..8b9589828855 100644
--- a/drivers/staging/comedi/drivers/8255_pci.c
+++ b/drivers/staging/comedi/drivers/8255_pci.c
@@ -190,24 +190,12 @@ static int pci_8255_mite_init(struct pci_dev *pcidev)
return 0;
}
-static int pci_8255_mmio(int dir, int port, int data, unsigned long iobase)
-{
- void __iomem *mmio_base = (void __iomem *)iobase;
-
- if (dir) {
- writeb(data, mmio_base + port);
- return 0;
- }
- return readb(mmio_base + port);
-}
-
static int pci_8255_auto_attach(struct comedi_device *dev,
unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
const struct pci_8255_boardinfo *board = NULL;
struct comedi_subdevice *s;
- bool is_mmio;
int ret;
int i;
@@ -228,9 +216,7 @@ static int pci_8255_auto_attach(struct comedi_device *dev,
return ret;
}
- is_mmio = (pci_resource_flags(pcidev, board->dio_badr) &
- IORESOURCE_MEM) != 0;
- if (is_mmio) {
+ if ((pci_resource_flags(pcidev, board->dio_badr) & IORESOURCE_MEM)) {
dev->mmio = pci_ioremap_bar(pcidev, board->dio_badr);
if (!dev->mmio)
return -ENOMEM;
@@ -248,16 +234,11 @@ static int pci_8255_auto_attach(struct comedi_device *dev,
return ret;
for (i = 0; i < board->n_8255; i++) {
- unsigned long iobase;
-
s = &dev->subdevices[i];
- if (is_mmio) {
- iobase = (unsigned long)(dev->mmio + (i * 4));
- ret = subdev_8255_init(dev, s, pci_8255_mmio, iobase);
- } else {
- iobase = dev->iobase + (i * 4);
- ret = subdev_8255_init(dev, s, NULL, iobase);
- }
+ if (dev->mmio)
+ ret = subdev_8255_mm_init(dev, s, NULL, i * I8255_SIZE);
+ else
+ ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE);
if (ret)
return ret;
}
@@ -265,18 +246,11 @@ static int pci_8255_auto_attach(struct comedi_device *dev,
return 0;
}
-static void pci_8255_detach(struct comedi_device *dev)
-{
- if (dev->mmio)
- iounmap(dev->mmio);
- comedi_pci_disable(dev);
-}
-
static struct comedi_driver pci_8255_driver = {
.driver_name = "8255_pci",
.module = THIS_MODULE,
.auto_attach = pci_8255_auto_attach,
- .detach = pci_8255_detach,
+ .detach = comedi_pci_detach,
};
static int pci_8255_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index 8873d4807a01..6bc9ef3b25b3 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_COMEDI_BOND) += comedi_bond.o
obj-$(CONFIG_COMEDI_TEST) += comedi_test.o
obj-$(CONFIG_COMEDI_PARPORT) += comedi_parport.o
obj-$(CONFIG_COMEDI_SERIAL2002) += serial2002.o
-obj-$(CONFIG_COMEDI_SKEL) += skel.o
# Comedi ISA drivers
obj-$(CONFIG_COMEDI_AMPLC_DIO200_ISA) += amplc_dio200.o
@@ -50,6 +49,7 @@ obj-$(CONFIG_COMEDI_NI_AT_A2150) += ni_at_a2150.o
obj-$(CONFIG_COMEDI_NI_AT_AO) += ni_at_ao.o
obj-$(CONFIG_COMEDI_NI_ATMIO) += ni_atmio.o
obj-$(CONFIG_COMEDI_NI_ATMIO16D) += ni_atmio16d.o
+obj-$(CONFIG_COMEDI_NI_LABPC_ISA) += ni_labpc.o
obj-$(CONFIG_COMEDI_PCMAD) += pcmad.o
obj-$(CONFIG_COMEDI_PCMDA12) += pcmda12.o
obj-$(CONFIG_COMEDI_PCMMIO) += pcmmio.o
@@ -125,6 +125,7 @@ obj-$(CONFIG_COMEDI_QUATECH_DAQP_CS) += quatech_daqp_cs.o
# Comedi USB drivers
obj-$(CONFIG_COMEDI_DT9812) += dt9812.o
+obj-$(CONFIG_COMEDI_NI_USB6501) += ni_usb6501.o
obj-$(CONFIG_COMEDI_USBDUX) += usbdux.o
obj-$(CONFIG_COMEDI_USBDUXFAST) += usbduxfast.o
obj-$(CONFIG_COMEDI_USBDUXSIGMA) += usbduxsigma.o
@@ -134,11 +135,10 @@ obj-$(CONFIG_COMEDI_VMK80XX) += vmk80xx.o
obj-$(CONFIG_COMEDI_MITE) += mite.o
obj-$(CONFIG_COMEDI_NI_TIO) += ni_tio.o
obj-$(CONFIG_COMEDI_NI_TIOCMD) += ni_tiocmd.o
-obj-$(CONFIG_COMEDI_NI_LABPC) += ni_labpc.o
+obj-$(CONFIG_COMEDI_NI_LABPC) += ni_labpc_common.o
obj-$(CONFIG_COMEDI_NI_LABPC_ISADMA) += ni_labpc_isadma.o
obj-$(CONFIG_COMEDI_8255) += 8255.o
obj-$(CONFIG_COMEDI_AMPLC_DIO200) += amplc_dio200_common.o
obj-$(CONFIG_COMEDI_AMPLC_PC236) += amplc_pc236_common.o
obj-$(CONFIG_COMEDI_DAS08) += das08.o
-obj-$(CONFIG_COMEDI_FC) += comedi_fc.o
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c
index de5843ab01ae..2e7fb218340f 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c
@@ -44,7 +44,7 @@ static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
struct addi_private *devpriv = dev->private;
unsigned short w_Address = CR_CHAN(insn->chanspec);
unsigned short w_Data;
@@ -59,7 +59,7 @@ static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev,
static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
this_board->interrupt(irq, d);
return IRQ_RETVAL(1);
@@ -67,7 +67,7 @@ static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
static int i_ADDI_Reset(struct comedi_device *dev)
{
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
this_board->reset(dev);
return 0;
@@ -77,7 +77,7 @@ static int addi_auto_attach(struct comedi_device *dev,
unsigned long context_unused)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
struct addi_private *devpriv;
struct comedi_subdevice *s;
int ret, n_subdevices;
@@ -268,13 +268,7 @@ static int addi_auto_attach(struct comedi_device *dev,
static void i_ADDI_Detach(struct comedi_device *dev)
{
- struct addi_private *devpriv = dev->private;
-
- if (devpriv) {
- if (dev->iobase)
- i_ADDI_Reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- }
- comedi_pci_disable(dev);
+ if (dev->iobase)
+ i_ADDI_Reset(dev);
+ comedi_pci_detach(dev);
}
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h
index a7400a25f620..e2a3ffeee5cf 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.h
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h
@@ -107,10 +107,9 @@ struct addi_private {
unsigned char b_DmaDoubleBuffer; /* we can use double buffering */
unsigned int ui_DmaActualBuffer; /* which buffer is used now */
unsigned short *ul_DmaBufferVirtual[2]; /* pointers to DMA buffer */
- unsigned int ul_DmaBufferHw[2]; /* hw address of DMA buff */
+ dma_addr_t ul_DmaBufferHw[2]; /* hw address of DMA buff */
unsigned int ui_DmaBufferSize[2]; /* size of dma buffer in bytes */
unsigned int ui_DmaBufferUsesize[2]; /* which size we may now used for transfer */
- unsigned int ui_DmaBufferPages[2]; /* number of pages in buffer */
unsigned char b_DigitalOutputRegister; /* Digital Output Register */
unsigned char b_OutputMemoryStatus;
unsigned char b_TimerSelectMode; /* Contain data written at iobase + 0C */
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
index aafc172f3a98..b731856c27da 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
@@ -179,7 +179,7 @@ static void addi_eeprom_read_di_info(struct comedi_device *dev,
unsigned long iobase,
unsigned short addr)
{
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
struct addi_private *devpriv = dev->private;
char *type = this_board->pc_EepromChip;
unsigned short tmp;
@@ -200,7 +200,7 @@ static void addi_eeprom_read_do_info(struct comedi_device *dev,
unsigned long iobase,
unsigned short addr)
{
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
struct addi_private *devpriv = dev->private;
char *type = this_board->pc_EepromChip;
unsigned short tmp;
@@ -218,7 +218,7 @@ static void addi_eeprom_read_timer_info(struct comedi_device *dev,
{
struct addi_private *devpriv = dev->private;
#if 0
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
char *type = this_board->pc_EepromChip;
unsigned short offset = 0;
unsigned short ntimers;
@@ -259,7 +259,7 @@ static void addi_eeprom_read_ao_info(struct comedi_device *dev,
unsigned long iobase,
unsigned short addr)
{
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
struct addi_private *devpriv = dev->private;
char *type = this_board->pc_EepromChip;
unsigned short tmp;
@@ -278,7 +278,7 @@ static void addi_eeprom_read_ai_info(struct comedi_device *dev,
unsigned long iobase,
unsigned short addr)
{
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
struct addi_private *devpriv = dev->private;
char *type = this_board->pc_EepromChip;
unsigned short offset;
@@ -315,7 +315,7 @@ static void addi_eeprom_read_ai_info(struct comedi_device *dev,
static void addi_eeprom_read_info(struct comedi_device *dev,
unsigned long iobase)
{
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
char *type = this_board->pc_EepromChip;
unsigned short size;
unsigned char nfuncs;
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c
index cad33f1a04fe..53bb51bd77b5 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c
@@ -477,6 +477,4 @@ static void apci035_interrupt(int irq, void *d)
/* 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 1e2fe66818e4..0ea081e1e119 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
@@ -172,17 +172,15 @@ static int apci1500_di_config(struct comedi_device *dev,
if (data[0] == 1) {
i_MaxChannel = 8;
- } /* if (data[0] == 1) */
- else {
+ } else {
if (data[0] == 2) {
i_MaxChannel = 6;
- } /* if(data[0]==2) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"The specified port event does not exist\n");
return -EINVAL;
- } /* else if(data[0]==2) */
- } /* else if (data[0] == 1) */
+ }
+ }
switch (data[1]) {
case 0:
data[1] = APCI1500_AND;
@@ -194,10 +192,10 @@ static int apci1500_di_config(struct comedi_device *dev,
data[1] = APCI1500_OR_PRIORITY;
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"The specified interrupt logic does not exist\n");
return -EINVAL;
- } /* switch(data[1]); */
+ }
i_Logic = data[1];
for (i_Count = i_MaxChannel, i = 0; i_Count > 0; i_Count--, i++) {
@@ -239,11 +237,11 @@ static int apci1500_di_config(struct comedi_device *dev,
case 5:
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_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 */
@@ -256,10 +254,10 @@ static int apci1500_di_config(struct comedi_device *dev,
if (data[1] == APCI1500_OR_PRIORITY
&& i_PatternTransition != 0) {
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_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 */
@@ -271,14 +269,14 @@ static int apci1500_di_config(struct comedi_device *dev,
((i_PatternTransition >>
i_Count) & 0x1);
- } /* for (i_Count = 0; i_Count < 8; i_Count++) */
+ }
if (i_PatternTransitionCount > 1) {
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_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,
@@ -347,13 +345,12 @@ static int apci1500_di_config(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_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 */
@@ -448,13 +445,12 @@ static int apci1500_di_config(struct comedi_device *dev,
outb(0xF4,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if (data[1] == APCI1500_OR) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"The choice for interrupt logic does not exist\n");
return -EINVAL;
- } /* elseif (data[1] == APCI1500_OR) */
- } /* if(data[0]==2) */
+ }
+ }
return insn->n;
}
@@ -518,13 +514,12 @@ static int apci1500_di_write(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if(i_Event1Status==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_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) {
@@ -555,19 +550,17 @@ static int apci1500_di_write(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
i_Event2InterruptStatus = 1;
- } /* if(i_Event2Status==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_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 {
- dev_warn(dev->hw_dev,
+ }
+ }
+ } else {
+ dev_warn(dev->class_dev,
"The port parameter is in error\n");
return -EINVAL;
- } /* else if (data[1] == 1 || data[0] == 2) */
+ }
break;
@@ -600,13 +593,12 @@ static int apci1500_di_write(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
i_Event1InterruptStatus = 0;
- } /* if(i_Event1Status==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_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) {
@@ -630,26 +622,25 @@ static int apci1500_di_write(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
i_Event2InterruptStatus = 0;
- } /* if(i_Event2Status==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+
+ dev_warn(dev->class_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 {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"The port parameter is in error\n");
return -EINVAL;
- } /* else if (data[1] == 1 || data[1] == 2) */
+ }
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"The option of START/STOP logic does not exist\n");
return -EINVAL;
- } /* switch(data[0]) */
+ }
return insn->n;
}
@@ -835,17 +826,15 @@ static int apci1500_do_write(struct comedi_device *dev,
unsigned int ui_Temp1;
unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */
- if (!devpriv->b_OutputMemoryStatus) {
+ if (!devpriv->b_OutputMemoryStatus)
ui_Temp = 0;
- } /* if(!devpriv->b_OutputMemoryStatus ) */
if (data[3] == 0) {
if (data[1] == 0) {
data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
outw(data[0],
devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP);
- } /* if(data[1]==0) */
- else {
+ } else {
if (data[1] == 1) {
switch (ui_NoOfChannel) {
@@ -876,20 +865,18 @@ static int apci1500_do_write(struct comedi_device *dev,
"chan spec wrong\n");
return -EINVAL; /* "sorry channel spec wrong " */
- } /* switch(ui_NoOfChannels) */
+ }
outw(data[0],
devpriv->i_IobaseAddon +
APCI1500_DIGITAL_OP);
- } /* if(data[1]==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"Specified channel not supported\n");
return -EINVAL;
- } /* else if(data[1]==1) */
- } /* elseif(data[1]==0) */
- } /* if(data[3]==0) */
- else {
+ }
+ }
+ } else {
if (data[3] == 1) {
if (data[1] == 0) {
data[0] = ~data[0] & 0x1;
@@ -903,8 +890,7 @@ static int apci1500_do_write(struct comedi_device *dev,
outw(data[0],
devpriv->i_IobaseAddon +
APCI1500_DIGITAL_OP);
- } /* if(data[1]==0) */
- else {
+ } else {
if (data[1] == 1) {
switch (ui_NoOfChannel) {
@@ -955,25 +941,23 @@ static int apci1500_do_write(struct comedi_device *dev,
"chan spec wrong\n");
return -EINVAL; /* "sorry channel spec wrong " */
- } /* switch(ui_NoOfChannels) */
+ }
outw(data[0],
devpriv->i_IobaseAddon +
APCI1500_DIGITAL_OP);
- } /* if(data[1]==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"Specified channel not supported\n");
return -EINVAL;
- } /* else if(data[1]==1) */
- } /* elseif(data[1]==0) */
- } /* if(data[3]==1); */
- else {
- dev_warn(dev->hw_dev,
+ }
+ }
+ } else {
+ dev_warn(dev->class_dev,
"Specified functionality does not exist\n");
return -EINVAL;
- } /* if else data[3]==1) */
- } /* if else data[3]==0) */
+ }
+ }
ui_Temp = data[0];
return insn->n;
}
@@ -1002,17 +986,16 @@ static int apci1500_timer_config(struct comedi_device *dev,
devpriv->tsk_Current = current;
-/* Selection of the input clock */
+ /* Selection of the input clock */
if (data[0] == 0 || data[0] == 1 || data[0] == 2) {
outw(data[0], devpriv->i_IobaseAddon + APCI1500_CLK_SELECT);
- } /* if(data[0]==0||data[0]==1||data[0]==2) */
- else {
+ } else {
if (data[0] != 3) {
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_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) */
+ }
+ }
/* Select the counter/timer */
switch (data[1]) {
case COUNTER1:
@@ -1025,10 +1008,10 @@ static int apci1500_timer_config(struct comedi_device *dev,
data[2] = APCI1500_TIMER;
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"This choice is not a timer nor a counter\n");
return -EINVAL;
- } /* switch(data[2]) */
+ }
/* Selecting single or continuous mode */
switch (data[4]) {
@@ -1039,10 +1022,10 @@ static int apci1500_timer_config(struct comedi_device *dev,
data[4] = APCI1500_SINGLE;
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_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 */
@@ -1133,18 +1116,16 @@ static int apci1500_timer_config(struct comedi_device *dev,
outb(0x2,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_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 {
- dev_warn(dev->hw_dev,
+ }
+ } else {
+ dev_warn(dev->class_dev,
"Error in selection of reload value\n");
return -EINVAL;
- } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */
+ }
i_TimerCounterWatchdogInterrupt = data[7];
i_TimerCounter1Init = 1;
break;
@@ -1158,10 +1139,10 @@ static int apci1500_timer_config(struct comedi_device *dev,
data[2] = APCI1500_TIMER;
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"This choice is not a timer nor a counter\n");
return -EINVAL;
- } /* switch(data[2]) */
+ }
/* Selecting single or continuous mode */
switch (data[4]) {
@@ -1172,10 +1153,10 @@ static int apci1500_timer_config(struct comedi_device *dev,
data[4] = APCI1500_SINGLE;
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"This option for single/continuous mode does not exist\n");
return -EINVAL;
- } /* switch(data[4]) */
+ }
/* Selecting software or hardware trigger */
switch (data[5]) {
@@ -1186,10 +1167,10 @@ static int apci1500_timer_config(struct comedi_device *dev,
data[5] = APCI1500_HARDWARE_TRIGGER;
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"This choice for software or hardware trigger does not exist\n");
return -EINVAL;
- } /* switch(data[5]) */
+ }
/* Selecting software or hardware gate */
switch (data[6]) {
@@ -1200,10 +1181,10 @@ static int apci1500_timer_config(struct comedi_device *dev,
data[6] = APCI1500_HARDWARE_GATE;
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_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;
@@ -1295,18 +1276,16 @@ static int apci1500_timer_config(struct comedi_device *dev,
outb(0x2,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_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 {
- dev_warn(dev->hw_dev,
+ }
+ } else {
+ dev_warn(dev->class_dev,
"Error in selection of reload value\n");
return -EINVAL;
- } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */
+ }
i_TimerCounterWatchdogInterrupt = data[7];
i_TimerCounter2Init = 1;
break;
@@ -1320,10 +1299,10 @@ static int apci1500_timer_config(struct comedi_device *dev,
data[2] = APCI1500_WATCHDOG;
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"This choice is not a watchdog nor a counter\n");
return -EINVAL;
- } /* switch(data[2]) */
+ }
/* Selecting single or continuous mode */
switch (data[4]) {
@@ -1334,10 +1313,10 @@ static int apci1500_timer_config(struct comedi_device *dev,
data[4] = APCI1500_SINGLE;
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"This option for single/continuous mode does not exist\n");
return -EINVAL;
- } /* switch(data[4]) */
+ }
/* Selecting software or hardware gate */
switch (data[6]) {
@@ -1348,10 +1327,10 @@ static int apci1500_timer_config(struct comedi_device *dev,
data[6] = APCI1500_HARDWARE_GATE;
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"This choice for software or hardware gate does not exist\n");
return -EINVAL;
- } /* switch(data[6]) */
+ }
/* Test if used for watchdog */
@@ -1360,10 +1339,9 @@ static int apci1500_timer_config(struct comedi_device *dev,
/* - Enables retrigger */
/* - Pulses output */
i_TimerCounterMode = data[2] | data[4] | 0x54;
- } /* if (data[2] == APCI1500_WATCHDOG) */
- else {
+ } 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)) {
@@ -1455,29 +1433,28 @@ static int apci1500_timer_config(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* elseif(data[2]==APCI1500_COUNTER) */
+ }
+
+ } else {
- } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */
- else {
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_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 {
- dev_warn(dev->hw_dev,
+ }
+ } else {
+ dev_warn(dev->class_dev,
"Error in selection of reload value\n");
return -EINVAL;
- } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */
+ }
i_TimerCounterWatchdogInterrupt = data[7];
i_WatchdogCounter3Init = 1;
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"The specified counter/timer option does not exist\n");
return -EINVAL;
- } /* switch(data[1]) */
+ }
i_CounterLogic = data[2];
return insn->n;
}
@@ -1502,12 +1479,11 @@ static int apci1500_timer_write(struct comedi_device *dev,
switch (data[1]) {
case START:
if (i_TimerCounter1Init == 1) {
- if (i_TimerCounterWatchdogInterrupt == 1) {
+ if (i_TimerCounterWatchdogInterrupt == 1)
i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */
- } /* if(i_TimerCounterWatchdogInterrupt==1) */
- else {
+ else
i_CommandAndStatusValue = 0xE4; /* disable the interrupt */
- } /* elseif(i_TimerCounterWatchdogInterrupt==1) */
+
/* Starts timer/counter 1 */
i_TimerCounter1Enabled = 1;
/* Selects the commands and status register */
@@ -1517,9 +1493,8 @@ static int apci1500_timer_write(struct comedi_device *dev,
outb(i_CommandAndStatusValue,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if( i_TimerCounter1Init==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"Counter/Timer1 not configured\n");
return -EINVAL;
}
@@ -1545,12 +1520,11 @@ static int apci1500_timer_write(struct comedi_device *dev,
/* Set Trigger and gate */
i_CommandAndStatusValue = 0x6;
- } /* if( i_TimerCounter1Enabled==1) */
- else {
+ } else {
/* Set Trigger */
i_CommandAndStatusValue = 0x2;
- } /* elseif(i_TimerCounter1Enabled==1) */
+ }
/* Selects the commands and status register */
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
@@ -1559,31 +1533,29 @@ static int apci1500_timer_write(struct comedi_device *dev,
outb(i_CommandAndStatusValue,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if( i_TimerCounter1Init==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"Counter/Timer1 not configured\n");
return -EINVAL;
}
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"The specified option for start/stop/trigger does not exist\n");
return -EINVAL;
- } /* switch(data[1]) */
+ }
break;
case COUNTER2:
switch (data[1]) {
case START:
if (i_TimerCounter2Init == 1) {
- if (i_TimerCounterWatchdogInterrupt == 1) {
+ if (i_TimerCounterWatchdogInterrupt == 1)
i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */
- } /* if(i_TimerCounterWatchdogInterrupt==1) */
- else {
+ else
i_CommandAndStatusValue = 0xE4; /* disable the interrupt */
- } /* elseif(i_TimerCounterWatchdogInterrupt==1) */
+
/* Starts timer/counter 2 */
i_TimerCounter2Enabled = 1;
/* Selects the commands and status register */
@@ -1593,9 +1565,8 @@ static int apci1500_timer_write(struct comedi_device *dev,
outb(i_CommandAndStatusValue,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if( i_TimerCounter2Init==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"Counter/Timer2 not configured\n");
return -EINVAL;
}
@@ -1620,12 +1591,11 @@ static int apci1500_timer_write(struct comedi_device *dev,
/* Set Trigger and gate */
i_CommandAndStatusValue = 0x6;
- } /* if( i_TimerCounter2Enabled==1) */
- else {
+ } else {
/* Set Trigger */
i_CommandAndStatusValue = 0x2;
- } /* elseif(i_TimerCounter2Enabled==1) */
+ }
/* Selects the commands and status register */
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
@@ -1634,30 +1604,28 @@ static int apci1500_timer_write(struct comedi_device *dev,
outb(i_CommandAndStatusValue,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if( i_TimerCounter2Init==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"Counter/Timer2 not configured\n");
return -EINVAL;
}
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"The specified option for start/stop/trigger does not exist\n");
return -EINVAL;
- } /* switch(data[1]) */
+ }
break;
case COUNTER3:
switch (data[1]) {
case START:
if (i_WatchdogCounter3Init == 1) {
- if (i_TimerCounterWatchdogInterrupt == 1) {
+ if (i_TimerCounterWatchdogInterrupt == 1)
i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */
- } /* if(i_TimerCounterWatchdogInterrupt==1) */
- else {
+ else
i_CommandAndStatusValue = 0xE4; /* disable the interrupt */
- } /* elseif(i_TimerCounterWatchdogInterrupt==1) */
+
/* Starts Watchdog/counter 3 */
i_WatchdogCounter3Enabled = 1;
/* Selects the commands and status register */
@@ -1668,9 +1636,8 @@ static int apci1500_timer_write(struct comedi_device *dev,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if( i_WatchdogCounter3init==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"Watchdog/Counter3 not configured\n");
return -EINVAL;
}
@@ -1698,12 +1665,11 @@ static int apci1500_timer_write(struct comedi_device *dev,
/* Set Trigger and gate */
i_CommandAndStatusValue = 0x6;
- } /* if( i_WatchdogCounter3Enabled==1) */
- else {
+ } else {
/* Set Trigger */
i_CommandAndStatusValue = 0x2;
- } /* elseif(i_WatchdogCounter3Enabled==1) */
+ }
/* Selects the commands and status register */
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
@@ -1712,9 +1678,8 @@ static int apci1500_timer_write(struct comedi_device *dev,
outb(i_CommandAndStatusValue,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if( i_WatchdogCounter3Init==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"Counter3 not configured\n");
return -EINVAL;
}
@@ -1730,30 +1695,29 @@ static int apci1500_timer_write(struct comedi_device *dev,
outb(0x6,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if( i_WatchdogCounter3Init==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"Watchdog 3 not configured\n");
return -EINVAL;
}
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"Wrong choice of watchdog/counter3\n");
return -EINVAL;
- } /* switch(data[2]) */
+ }
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"The specified option for start/stop/trigger does not exist\n");
return -EINVAL;
- } /* switch(data[1]) */
+ }
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"The specified choice for counter/watchdog/timer does not exist\n");
return -EINVAL;
- } /* switch(data[0]) */
+ }
return insn->n;
}
@@ -1778,12 +1742,11 @@ static int apci1500_timer_bits(struct comedi_device *dev,
/* Set RCC and gate */
i_CommandAndStatusValue = 0xC;
- } /* if( i_TimerCounter1Init==1) */
- else {
+ } else {
/* Set RCC */
i_CommandAndStatusValue = 0x8;
- } /* elseif(i_TimerCounter1Init==1) */
+ }
/* Selects the commands and status register */
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
@@ -1808,12 +1771,11 @@ static int apci1500_timer_bits(struct comedi_device *dev,
data[0] =
data[0] | inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if( i_TimerCounter1Init==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"Timer/Counter1 not configured\n");
return -EINVAL;
- } /* elseif( i_TimerCounter1Init==1) */
+ }
break;
case COUNTER2:
/* Read counter/timer2 */
@@ -1822,12 +1784,11 @@ static int apci1500_timer_bits(struct comedi_device *dev,
/* Set RCC and gate */
i_CommandAndStatusValue = 0xC;
- } /* if( i_TimerCounter2Init==1) */
- else {
+ } else {
/* Set RCC */
i_CommandAndStatusValue = 0x8;
- } /* elseif(i_TimerCounter2Init==1) */
+ }
/* Selects the commands and status register */
outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
@@ -1852,12 +1813,11 @@ static int apci1500_timer_bits(struct comedi_device *dev,
data[0] =
data[0] | inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if( i_TimerCounter2Init==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"Timer/Counter2 not configured\n");
return -EINVAL;
- } /* elseif( i_TimerCounter2Init==1) */
+ }
break;
case COUNTER3:
/* Read counter/watchdog2 */
@@ -1866,12 +1826,11 @@ static int apci1500_timer_bits(struct comedi_device *dev,
/* Set RCC and gate */
i_CommandAndStatusValue = 0xC;
- } /* if( i_TimerCounter2Init==1) */
- else {
+ } else {
/* Set RCC */
i_CommandAndStatusValue = 0x8;
- } /* elseif(i_WatchdogCounter3Init==1) */
+ }
/* Selects the commands and status register */
outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
@@ -1896,18 +1855,17 @@ static int apci1500_timer_bits(struct comedi_device *dev,
data[0] =
data[0] | inb(devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- } /* if( i_WatchdogCounter3Init==1) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"WatchdogCounter3 not configured\n");
return -EINVAL;
- } /* elseif( i_WatchdogCounter3Init==1) */
+ }
break;
default:
- dev_warn(dev->hw_dev,
+ dev_warn(dev->class_dev,
"The choice of timer/counter/watchdog does not exist\n");
return -EINVAL;
- } /* switch(data[0]) */
+ }
return insn->n;
}
@@ -1946,17 +1904,15 @@ static int apci1500_do_bits(struct comedi_device *dev,
outl(0x0, devpriv->i_IobaseAmcc + 0x38);
if (data[0] == 1) {
i_Constant = 0xC0;
- } /* if(data[0]==1) */
- else {
+ } else {
if (data[0] == 0) {
i_Constant = 0x00;
- } /* if{data[0]==0) */
- else {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_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,
@@ -2062,6 +2018,8 @@ static void apci1500_interrupt(int irq, void *d)
struct addi_private *devpriv = dev->private;
unsigned int ui_InterruptStatus = 0;
int i_RegValue = 0;
+
+ /* Clear the interrupt mask */
i_InterruptMask = 0;
/* Read the board interrupt status */
@@ -2071,10 +2029,7 @@ static void apci1500_interrupt(int irq, void *d)
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);
@@ -2109,11 +2064,10 @@ static void apci1500_interrupt(int irq, void *d)
i_InputChannel = 1 + (i_RegValue >> 1);
- } /* if(i_Logic==APCI1500_OR_PRIORITY) */
- else {
+ } else {
i_InputChannel = 0;
- } /* 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,
@@ -2146,17 +2100,16 @@ static void apci1500_interrupt(int irq, void *d)
if (i_RegValue & 0x80) {
i_InterruptMask =
i_InterruptMask | 0x40;
- } /* if (i_RegValue & 0x80) */
+ }
if (i_RegValue & 0x40) {
i_InterruptMask =
i_InterruptMask | 0x80;
- } /* if (i_RegValue & 0x40) */
- } /* if (i_RegValue) */
- else {
+ }
+ } else {
i_InterruptMask = i_InterruptMask | 2;
- } /* if (i_RegValue) */
- } /* if ((i_RegValue & 0x60) == 0x60) */
+ }
+ }
/* Selects the command and status register of timer 1 */
outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
@@ -2174,7 +2127,7 @@ static void apci1500_interrupt(int irq, void *d)
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);
@@ -2191,7 +2144,7 @@ static void apci1500_interrupt(int irq, void *d)
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
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,
@@ -2208,13 +2161,11 @@ static void apci1500_interrupt(int irq, void *d)
outb(i_RegValue,
devpriv->iobase +
APCI1500_Z8536_CONTROL_REGISTER);
- if (i_CounterLogic == APCI1500_COUNTER) {
+ if (i_CounterLogic == APCI1500_COUNTER)
i_InterruptMask = i_InterruptMask | 0x10;
- } /* if(i_CounterLogic==APCI1500_COUNTER) */
- else {
+ else
i_InterruptMask = i_InterruptMask | 0x20;
- }
- } /* if ((i_RegValue & 0x60) == 0x60) */
+ }
send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
/* Enable all Interrupts */
@@ -2224,13 +2175,11 @@ static void apci1500_interrupt(int irq, void *d)
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 {
- dev_warn(dev->hw_dev,
+ } else {
+ dev_warn(dev->class_dev,
"Interrupt from unknown source\n");
- } /* else if ((ui_InterruptStatus & 0x800000) == 0x800000) */
- return;
+ }
}
static int apci1500_reset(struct comedi_device *dev)
@@ -2379,36 +2328,36 @@ static int apci1500_reset(struct comedi_device *dev)
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 */
+ /* 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 */
+ /* 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 */
+ /* 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 */
+ /* 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 */
+ /* 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 */
+ /* Deactivates all interrupts */
outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-/* Selects the command and status register of timer 3*/
+ /* 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 */
+ /* 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 8a613ae0acba..98de96953a29 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c
@@ -1,28 +1,3 @@
-/*
- * 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.
- *
- */
-
-#define APCI1564_ADDRESS_RANGE 128
-
/* Digital Input IRQ Function Selection */
#define APCI1564_DI_INT_OR (0 << 1)
#define APCI1564_DI_INT_AND (1 << 1)
@@ -32,10 +7,10 @@
#define APCI1564_DI_INT_DISABLE 0xfffffffb
/* Digital Output Interrupt Enable Disable. */
-#define APCI1564_DIGITAL_OP_VCC_INTERRUPT_ENABLE 0x1
-#define APCI1564_DIGITAL_OP_VCC_INTERRUPT_DISABLE 0xfffffffe
-#define APCI1564_DIGITAL_OP_CC_INTERRUPT_ENABLE 0x2
-#define APCI1564_DIGITAL_OP_CC_INTERRUPT_DISABLE 0xfffffffd
+#define APCI1564_DO_VCC_INT_ENABLE 0x1
+#define APCI1564_DO_VCC_INT_DISABLE 0xfffffffe
+#define APCI1564_DO_CC_INT_ENABLE 0x2
+#define APCI1564_DO_CC_INT_DISABLE 0xfffffffd
/* TIMER COUNTER WATCHDOG DEFINES */
#define ADDIDATA_TIMER 0
@@ -76,55 +51,21 @@
#define APCI1564_TIMER_WARN_TIMEBASE_REG 0x64
/*
- * dev>iobase Register Map
+ * 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))
-
-/*
- * 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 apci1564_private *devpriv = dev->private;
- unsigned int ul_Command = 0;
-
- if ((data[0] != 0) && (data[0] != 1)) {
- dev_err(dev->class_dev, "Data should be 1 or 0\n");
- return -EINVAL;
- }
-
- if (data[1] == 1)
- ul_Command = ul_Command | 0x1;
- else
- ul_Command = ul_Command & 0xFFFFFFFE;
-
- if (data[2] == 1)
- ul_Command = ul_Command | 0x2;
- else
- ul_Command = ul_Command & 0xFFFFFFFD;
-
- outl(ul_Command, devpriv->amcc_iobase + APCI1564_DO_INT_CTRL_REG);
- devpriv->tsk_current = current;
- return insn->n;
-}
+#define APCI1564_COUNTER_REG(x) (0x00 + ((x) * 0x20))
+#define APCI1564_COUNTER_RELOAD_REG(x) (0x04 + ((x) * 0x20))
+#define APCI1564_COUNTER_TIMEBASE_REG(x) (0x08 + ((x) * 0x20))
+#define APCI1564_COUNTER_CTRL_REG(x) (0x0c + ((x) * 0x20))
+#define APCI1564_COUNTER_STATUS_REG(x) (0x10 + ((x) * 0x20))
+#define APCI1564_COUNTER_IRQ_REG(x) (0x14 + ((x) * 0x20))
+#define APCI1564_COUNTER_WARN_TIMEVAL_REG(x) (0x18 + ((x) * 0x20))
+#define APCI1564_COUNTER_WARN_TIMEBASE_REG(x) (0x1c + ((x) * 0x20))
/*
- * Configures The Timer, Counter or Watchdog
+ * Configures The Timer or Counter
*
- * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog
+ * data[0] Configure as: 0 = Timer, 1 = Counter
* data[1] 1 = Enable Interrupt, 0 = Disable Interrupt
* data[2] Time Unit
* data[3] Reload Value
@@ -141,14 +82,7 @@ static int apci1564_timer_config(struct comedi_device *dev,
unsigned int ul_Command1 = 0;
devpriv->tsk_current = current;
- if (data[0] == ADDIDATA_WATCHDOG) {
- devpriv->timer_select_mode = ADDIDATA_WATCHDOG;
-
- /* Disable the watchdog */
- outl(0x0, devpriv->amcc_iobase + APCI1564_WDOG_CTRL_REG);
- /* Loading the Reload value */
- outl(data[3], devpriv->amcc_iobase + APCI1564_WDOG_RELOAD_REG);
- } else if (data[0] == ADDIDATA_TIMER) {
+ if (data[0] == ADDIDATA_TIMER) {
/* First Stop The Timer */
ul_Command1 = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);
ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
@@ -162,14 +96,14 @@ static int apci1564_timer_config(struct comedi_device *dev,
outl(0x0, devpriv->amcc_iobase + APCI1564_DI_IRQ_REG);
outl(0x0, devpriv->amcc_iobase + APCI1564_DO_IRQ_REG);
outl(0x0, devpriv->amcc_iobase + APCI1564_WDOG_IRQ_REG);
- outl(0x0,
- dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1));
- outl(0x0,
- dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2));
- outl(0x0,
- dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3));
- outl(0x0,
- dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4));
+ outl(0x0, dev->iobase +
+ APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER1));
+ outl(0x0, dev->iobase +
+ APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER2));
+ outl(0x0, dev->iobase +
+ APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER3));
+ outl(0x0, dev->iobase +
+ APCI1564_COUNTER_IRQ_REG(APCI1564_COUNTER4));
} else {
/* disable Timer interrupt */
outl(0x0, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);
@@ -190,13 +124,16 @@ static int apci1564_timer_config(struct comedi_device *dev,
devpriv->mode_select_register = data[5];
/* First Stop The Counter */
- ul_Command1 = inl(dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
+ ul_Command1 = inl(dev->iobase +
+ APCI1564_COUNTER_CTRL_REG(data[5] - 1));
ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
/* Stop The Timer */
- outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
+ outl(ul_Command1, dev->iobase +
+ APCI1564_COUNTER_CTRL_REG(data[5] - 1));
/* Set the reload value */
- outl(data[3], dev->iobase + APCI1564_TCW_RELOAD_REG(data[5] - 1));
+ outl(data[3], dev->iobase +
+ APCI1564_COUNTER_RELOAD_REG(data[5] - 1));
/* Set the mode : */
/* - Disable the hardware */
@@ -209,26 +146,28 @@ static int apci1564_timer_config(struct comedi_device *dev,
ul_Command1 =
(ul_Command1 & 0xFFFC19E2UL) | 0x80000UL |
(unsigned int) ((unsigned int) data[4] << 16UL);
- outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
+ outl(ul_Command1, dev->iobase +
+ APCI1564_COUNTER_CTRL_REG(data[5] - 1));
/* Enable or Disable Interrupt */
ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1);
- outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
+ outl(ul_Command1, dev->iobase +
+ APCI1564_COUNTER_CTRL_REG(data[5] - 1));
/* Set the Up/Down selection */
ul_Command1 = (ul_Command1 & 0xFFFBF9FFUL) | (data[6] << 18);
- outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1));
+ outl(ul_Command1, dev->iobase +
+ APCI1564_COUNTER_CTRL_REG(data[5] - 1));
} else {
dev_err(dev->class_dev, "Invalid subdevice.\n");
}
-
return insn->n;
}
/*
- * Start / Stop The Selected Timer, Counter or Watchdog
+ * Start / Stop The Selected Timer or Counter
*
- * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog
+ * data[0] Configure as: 0 = Timer, 1 = Counter
* data[1] 0 = Stop, 1 = Start, 2 = Trigger Clear (Only Counter)
*/
static int apci1564_timer_write(struct comedi_device *dev,
@@ -239,23 +178,6 @@ static int apci1564_timer_write(struct comedi_device *dev,
struct apci1564_private *devpriv = dev->private;
unsigned int ul_Command1 = 0;
- if (devpriv->timer_select_mode == ADDIDATA_WATCHDOG) {
- switch (data[1]) {
- case 0: /* stop the watchdog */
- /* disable the watchdog */
- outl(0x0, devpriv->amcc_iobase + APCI1564_WDOG_CTRL_REG);
- break;
- case 1: /* start the watchdog */
- outl(0x0001, devpriv->amcc_iobase + APCI1564_WDOG_CTRL_REG);
- break;
- case 2: /* Software trigger */
- outl(0x0201, devpriv->amcc_iobase + APCI1564_WDOG_CTRL_REG);
- break;
- default:
- dev_err(dev->class_dev, "Specified functionality does not exist.\n");
- return -EINVAL;
- }
- }
if (devpriv->timer_select_mode == ADDIDATA_TIMER) {
if (data[1] == 1) {
ul_Command1 = inl(devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);
@@ -270,11 +192,10 @@ static int apci1564_timer_write(struct comedi_device *dev,
ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
outl(ul_Command1, devpriv->amcc_iobase + APCI1564_TIMER_CTRL_REG);
}
- }
- if (devpriv->timer_select_mode == ADDIDATA_COUNTER) {
+ } else if (devpriv->timer_select_mode == ADDIDATA_COUNTER) {
ul_Command1 =
inl(dev->iobase +
- APCI1564_TCW_CTRL_REG(devpriv->mode_select_register - 1));
+ APCI1564_COUNTER_CTRL_REG(devpriv->mode_select_register - 1));
if (data[1] == 1) {
/* Start the Counter subdevice */
ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL;
@@ -287,13 +208,15 @@ static int apci1564_timer_write(struct comedi_device *dev,
ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400;
}
outl(ul_Command1, dev->iobase +
- APCI1564_TCW_CTRL_REG(devpriv->mode_select_register - 1));
+ APCI1564_COUNTER_CTRL_REG(devpriv->mode_select_register - 1));
+ } else {
+ dev_err(dev->class_dev, "Invalid subdevice.\n");
}
return insn->n;
}
/*
- * Read The Selected Timer, Counter or Watchdog
+ * Read The Selected Timer or Counter
*/
static int apci1564_timer_read(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -303,11 +226,7 @@ static int apci1564_timer_read(struct comedi_device *dev,
struct apci1564_private *devpriv = dev->private;
unsigned int ul_Command1 = 0;
- if (devpriv->timer_select_mode == ADDIDATA_WATCHDOG) {
- /* Stores the status of the Watchdog */
- data[0] = inl(devpriv->amcc_iobase + APCI1564_WDOG_STATUS_REG) & 0x1;
- data[1] = inl(devpriv->amcc_iobase + APCI1564_WDOG_REG);
- } else if (devpriv->timer_select_mode == ADDIDATA_TIMER) {
+ if (devpriv->timer_select_mode == ADDIDATA_TIMER) {
/* Stores the status of the Timer */
data[0] = inl(devpriv->amcc_iobase + APCI1564_TIMER_STATUS_REG) & 0x1;
@@ -317,10 +236,10 @@ static int apci1564_timer_read(struct comedi_device *dev,
/* Read the Counter Actual Value. */
data[0] =
inl(dev->iobase +
- APCI1564_TCW_REG(devpriv->mode_select_register - 1));
+ APCI1564_COUNTER_REG(devpriv->mode_select_register - 1));
ul_Command1 =
inl(dev->iobase +
- APCI1564_TCW_STATUS_REG(devpriv->mode_select_register - 1));
+ APCI1564_COUNTER_STATUS_REG(devpriv->mode_select_register - 1));
/* Get the software trigger status */
data[1] = (unsigned char) ((ul_Command1 >> 1) & 1);
@@ -333,10 +252,8 @@ static int apci1564_timer_read(struct comedi_device *dev,
/* Get the overflow status */
data[4] = (unsigned char) ((ul_Command1 >> 0) & 1);
- } else if ((devpriv->timer_select_mode != ADDIDATA_TIMER)
- && (devpriv->timer_select_mode != ADDIDATA_WATCHDOG)
- && (devpriv->timer_select_mode != ADDIDATA_COUNTER)) {
- dev_err(dev->class_dev, "Invalid Subdevice!\n");
+ } else {
+ dev_err(dev->class_dev, "Invalid subdevice.\n");
}
return insn->n;
}
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
index 77cee876a374..2950815b65f4 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
@@ -241,26 +241,19 @@ static const struct comedi_lrange range_apci3120_ao = {
/* FUNCTION DEFINITIONS */
-
-/*
-+----------------------------------------------------------------------------+
-| ANALOG INPUT SUBDEVICE |
-+----------------------------------------------------------------------------+
-*/
-
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);
+ const struct addi_board *this_board = dev->board_ptr;
struct addi_private *devpriv = dev->private;
unsigned int i;
if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
return -1;
- /* Check for Conversion time to be added ?? */
+ /* Check for Conversion time to be added */
devpriv->ui_EocEosConversionTime = data[2];
if (data[0] == APCI3120_EOS_MODE) {
@@ -282,7 +275,6 @@ static int apci3120_ai_insn_config(struct comedi_device *dev,
else
devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
/* Copy channel list and Range List to devpriv */
-
devpriv->ui_AiNbrofChannels = data[3];
for (i = 0; i < devpriv->ui_AiNbrofChannels; i++)
devpriv->ui_AiChannelList[i] = data[4 + i];
@@ -311,7 +303,7 @@ static int apci3120_setup_chan_list(struct comedi_device *dev,
char check)
{
struct addi_private *devpriv = dev->private;
- unsigned int i; /* , differencial=0, bipolar=0; */
+ unsigned int i;
unsigned int gain;
unsigned short us_TmpValue;
@@ -326,7 +318,7 @@ static int apci3120_setup_chan_list(struct comedi_device *dev,
if (check)
return 1;
- /* Code to set the PA and PR...Here it set PA to 0.. */
+ /* Code to set the PA and PR...Here it set PA to 0 */
devpriv->us_OutputRegister =
devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
@@ -334,16 +326,16 @@ static int apci3120_setup_chan_list(struct comedi_device *dev,
for (i = 0; i < n_chan; i++) {
/* store range list to card */
- us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number; */
+ us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number */
if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES)
us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */
else
- us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar...... */
+ us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar */
gain = CR_RANGE(chanlist[i]); /* get gain number */
us_TmpValue |= ((gain & 0x03) << 4); /* <<4 for G0 and G1 bit in RAM */
- us_TmpValue |= i << 8; /* To select the RAM LOCATION.... */
+ us_TmpValue |= i << 8; /* To select the RAM LOCATION */
outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
}
return 1; /* we can serve this with scan logic */
@@ -359,7 +351,7 @@ static int apci3120_ai_insn_read(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
struct addi_private *devpriv = dev->private;
unsigned short us_ConvertTiming, us_TmpValue, i;
unsigned char b_Tmp;
@@ -370,24 +362,21 @@ static int apci3120_ai_insn_read(struct comedi_device *dev,
else
us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */
- /* this_board->ai_read(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
-
/* Clear software registers */
devpriv->b_TimerSelectMode = 0;
devpriv->b_ModeSelectRegister = 0;
devpriv->us_OutputRegister = 0;
-/* devpriv->b_DigitalOutputRegister=0; */
if (insn->unused[0] == 222) { /* second insn read */
for (i = 0; i < insn->n; i++)
data[i] = devpriv->ui_AiReadData[i];
} else {
devpriv->tsk_Current = current; /* Save the current process task structure */
-/*
- * Testing if board have the new Quartz and calculate the time value
- * to set in the timer
- */
+ /*
+ * Testing if board have the new Quartz and calculate the time value
+ * to set in the timer
+ */
us_TmpValue =
(unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
@@ -406,9 +395,9 @@ static int apci3120_ai_insn_read(struct comedi_device *dev,
case APCI3120_EOC_MODE:
-/*
- * Testing the interrupt flag and set the EOC bit Clears the FIFO
- */
+ /*
+ * Testing the interrupt flag and set the EOC bit Clears the FIFO
+ */
inw(devpriv->iobase + APCI3120_RESET_FIFO);
/* Initialize the sequence array */
@@ -556,7 +545,6 @@ static int apci3120_ai_insn_read(struct comedi_device *dev,
inw(devpriv->iobase + APCI3120_RD_STATUS);
/* Sets gate 0 */
-
devpriv->us_OutputRegister =
devpriv->
us_OutputRegister | APCI3120_ENABLE_TIMER0;
@@ -583,7 +571,7 @@ static int apci3120_ai_insn_read(struct comedi_device *dev,
data[i] = (unsigned int) us_TmpValue;
}
- devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults. */
+ devpriv->b_InterruptMode = APCI3120_EOC_MODE; /* Restore defaults */
}
break;
@@ -591,7 +579,7 @@ static int apci3120_ai_insn_read(struct comedi_device *dev,
dev_err(dev->class_dev, "inputs wrong\n");
}
- devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable; */
+ devpriv->ui_EocEosConversionTime = 0; /* re initializing the variable */
}
return insn->n;
@@ -623,10 +611,10 @@ static int apci3120_reset(struct comedi_device *dev)
devpriv->us_OutputRegister = 0;
outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
-/*
- * Code to set the all anolog o/p channel to 0v 8191 is decimal
- * value for zero(0 v)volt in bipolar mode(default)
- */
+ /*
+ * Code to set the all anolog o/p channel to 0v 8191 is decimal
+ * value for zero(0 v)volt in bipolar mode(default)
+ */
outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 1 */
outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 2 */
outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 3 */
@@ -637,9 +625,6 @@ static int apci3120_reset(struct comedi_device *dev)
outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 7 */
outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 8 */
- /* Reset digital output to L0W */
-
-/* ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */
udelay(10);
inw(dev->iobase + 0); /* make a dummy read */
@@ -689,12 +674,6 @@ static int apci3120_cancel(struct comedi_device *dev,
/* Disable BUS Master PCI */
outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
- /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL),
- * devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR); stop amcc irqs */
-
- /* outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS),
- * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */
-
/* Disable ext trigger */
apci3120_exttrig_disable(dev);
@@ -802,7 +781,7 @@ static int apci3120_cyclic_ai(int mode,
struct comedi_device *dev,
struct comedi_subdevice *s)
{
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
struct addi_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned char b_Tmp;
@@ -811,53 +790,29 @@ static int apci3120_cyclic_ai(int mode,
0, ui_TimerValue0, ui_ConvertTiming;
unsigned short us_TmpValue;
- /*******************/
/* Resets the FIFO */
- /*******************/
inb(dev->iobase + APCI3120_RESET_FIFO);
- /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
- /* inw(dev->iobase+APCI3120_RD_STATUS); */
- /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
-
devpriv->ai_running = 1;
/* clear software registers */
devpriv->b_TimerSelectMode = 0;
devpriv->us_OutputRegister = 0;
devpriv->b_ModeSelectRegister = 0;
- /* devpriv->b_DigitalOutputRegister=0; */
-
- /* COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition */
- /****************************/
/* Clear Timer Write TC int */
- /****************************/
outl(APCI3120_CLEAR_WRITE_TC_INT,
devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
- /************************************/
- /* Clears the timer status register */
- /************************************/
-
- /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
- /* inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER); */
- /* inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); */
- /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
-
- /**************************/
/* Disables All Timer */
/* Sets PR and PA to 0 */
- /**************************/
devpriv->us_OutputRegister = devpriv->us_OutputRegister &
APCI3120_DISABLE_TIMER0 &
APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
- /*******************/
/* Resets the FIFO */
- /*******************/
/* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
inb(devpriv->iobase + APCI3120_RESET_FIFO);
/* END JK 07.05.04: Comparison between WIN32 and Linux driver */
@@ -866,44 +821,21 @@ static int apci3120_cyclic_ai(int mode,
s->async->cur_chan = 0;
devpriv->ui_DmaActualBuffer = 0;
- /* value for timer2 minus -2 has to be done .....dunno y?? */
+ /* value for timer2 minus -2 has to be done */
ui_TimerValue2 = cmd->stop_arg - 2;
ui_ConvertTiming = cmd->convert_arg;
if (mode == 2)
ui_DelayTiming = cmd->scan_begin_arg;
- /**********************************/
/* Initializes the sequence array */
- /**********************************/
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);
-/*** EL241003 : add this section in comment because floats must not be used
- if((us_TmpValue & 0x00B0)==0x00B0)
- {
- f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
- ui_TimerValue0=(unsigned int)f_ConvertValue;
- if (mode==2)
- {
- f_DelayValue = (((float)ui_DelayTiming * 0.00002) - 2);
- ui_TimerValue1 = (unsigned int) f_DelayValue;
- }
- }
- else
- {
- f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
- ui_TimerValue0=(unsigned int)f_ConvertValue;
- if (mode == 2)
- {
- f_DelayValue = (((float)ui_DelayTiming * 0.000012926) - 1);
- ui_TimerValue1 = (unsigned int) f_DelayValue;
- }
- }
-***********************************************************************************************/
-/*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
+
+ /* EL241003 Begin: add this section to replace floats calculation by integer calculations */
/* EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001 */
if ((us_TmpValue & 0x00B0) == 0x00B0
|| !strcmp(this_board->pc_DriverName, "apci3001")) {
@@ -926,7 +858,7 @@ static int apci3120_cyclic_ai(int mode,
ui_TimerValue1 = ui_TimerValue1 / 1000000;
}
}
-/*** EL241003 End ******************************************************************************/
+ /* EL241003 End */
if (devpriv->b_ExttrigEnable == APCI3120_ENABLE)
apci3120_exttrig_enable(dev); /* activate EXT trigger */
@@ -985,15 +917,8 @@ static int apci3120_cyclic_ai(int mode,
break;
}
- /* ##########common for all modes################# */
-
- /***********************/
- /* Clears the SCAN bit */
- /***********************/
-
+ /* common for all modes */
/* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
- /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN; */
-
devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
APCI3120_DISABLE_SCAN;
/* END JK 07.05.04: Comparison between WIN32 and Linux driver */
@@ -1015,10 +940,10 @@ static int apci3120_cyclic_ai(int mode,
dev->iobase + APCI3120_WRITE_MODE_SELECT);
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)
- */
+ /*
+ * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to
+ * disable it (Set Bit D14 to 0)
+ */
devpriv->us_OutputRegister =
devpriv->
us_OutputRegister & APCI3120_DISABLE_TIMER2;
@@ -1084,14 +1009,9 @@ static int apci3120_cyclic_ai(int mode,
/* 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 */
- /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
devpriv->b_InterruptMode = APCI3120_DMA_MODE;
- /************************************/
/* Disables the EOC, EOS interrupt */
- /************************************/
devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
@@ -1114,7 +1034,7 @@ static int apci3120_cyclic_ai(int mode,
dmalen0;
}
- if (cmd->flags & TRIG_WAKE_EOS) {
+ if (cmd->flags & CMDF_WAKE_EOS) {
/* don't we want wake up every scan? */
if (dmalen0 > scan_bytes) {
dmalen0 = scan_bytes;
@@ -1139,17 +1059,15 @@ static int apci3120_cyclic_ai(int mode,
/* Initialize DMA */
-/*
- * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
- * register 1
- */
+ /*
+ * Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS
+ * register 1
+ */
ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
/* changed since 16 bit interface for add on */
- /*********************/
/* ENABLE BUS MASTER */
- /*********************/
outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
devpriv->i_IobaseAddon + 2);
@@ -1158,112 +1076,88 @@ static int apci3120_cyclic_ai(int mode,
outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
devpriv->i_IobaseAddon + 2);
-/*
- * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
- * driver
- */
+ /*
+ * TO VERIFIED BEGIN JK 07.05.04: Comparison between WIN32 and Linux
+ * driver
+ */
outw(0x1000, devpriv->i_IobaseAddon + 2);
/* END JK 07.05.04: Comparison between WIN32 and Linux driver */
/* 2 No change */
/* A2P FIFO MANAGEMENT */
/* A2P fifo reset & transfer control enable */
-
- /***********************/
- /* A2P FIFO MANAGEMENT */
- /***********************/
outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
APCI3120_AMCC_OP_MCSR);
-/*
- * 3
- * beginning address of dma buf The 32 bit address of dma buffer
- * is converted into two 16 bit addresses Can done by using _attach
- * and put into into an array array used may be for differnet pages
- */
+ /*
+ * 3
+ * beginning address of dma buf The 32 bit address of dma buffer
+ * is converted into two 16 bit addresses Can done by using _attach
+ * and put into into an array array used may be for differnet pages
+ */
/* DMA Start Address Low */
outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
devpriv->i_IobaseAddon + 2);
- /*************************/
/* DMA Start Address High */
- /*************************/
outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
outw((devpriv->ul_DmaBufferHw[0] / 65536),
devpriv->i_IobaseAddon + 2);
-/*
- * 4
- * amount of bytes to be transferred set transfer count used ADDON
- * MWTC register commented testing
- * outl(devpriv->ui_DmaBufferUsesize[0],
- * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
- */
+ /*
+ * 4
+ * amount of bytes to be transferred set transfer count used ADDON
+ * MWTC register commented testing
+ */
- /**************************/
/* Nbr of acquisition LOW */
- /**************************/
outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
devpriv->i_IobaseAddon + 2);
- /***************************/
/* Nbr of acquisition HIGH */
- /***************************/
outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
devpriv->i_IobaseAddon + 2);
-/*
- * 5
- * To configure A2P FIFO testing outl(
- * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
- */
+ /*
+ * 5
+ * To configure A2P FIFO testing outl(
+ * FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
+ */
- /******************/
/* A2P FIFO RESET */
- /******************/
-/*
- * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
- * driver
- */
+ /*
+ * TO VERIFY BEGIN JK 07.05.04: Comparison between WIN32 and Linux
+ * driver
+ */
outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
/* END JK 07.05.04: Comparison between WIN32 and Linux driver */
-/*
- * 6
- * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
- * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
- */
-
- /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
- /* outw(3,devpriv->i_IobaseAddon + 4); */
- /* END JK 07.05.04: Comparison between WIN32 and Linux driver */
-
-/*
- * 7
- * initialise end of dma interrupt AINT_WRITE_COMPL =
- * ENABLE_WRITE_TC_INT(ADDI)
- */
- /***************************************************/
+ /*
+ * 6
+ * ENABLE A2P FIFO WRITE AND ENABLE AMWEN AMWEN_ENABLE |
+ * A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
+ */
+
+ /*
+ * 7
+ * initialise end of dma interrupt AINT_WRITE_COMPL =
+ * ENABLE_WRITE_TC_INT(ADDI)
+ */
/* A2P FIFO CONFIGURATE, END OF DMA intERRUPT INIT */
- /***************************************************/
outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
APCI3120_ENABLE_WRITE_TC_INT),
devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
/* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
- /******************************************/
/* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
- /******************************************/
outw(3, devpriv->i_IobaseAddon + 4);
/* END JK 07.05.04: Comparison between WIN32 and Linux driver */
- /******************/
/* A2P FIFO RESET */
- /******************/
/* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */
outl(0x04000000UL,
devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
@@ -1323,8 +1217,8 @@ static int apci3120_ai_cmd(struct comedi_device *dev,
if (cmd->scan_begin_src == TRIG_FOLLOW)
return apci3120_cyclic_ai(1, dev, s);
- else /* TRIG_TIMER */
- return apci3120_cyclic_ai(2, dev, s);
+ /* TRIG_TIMER */
+ return apci3120_cyclic_ai(2, dev, s);
}
/*
@@ -1416,11 +1310,11 @@ static void apci3120_interrupt_dma(int irq, void *d)
outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
outw(high_word, devpriv->i_IobaseAddon + 2);
-/*
- * To configure A2P FIFO
- * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
- * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
- */
+ /*
+ * To configure A2P FIFO
+ * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
+ * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
+ */
outw(3, devpriv->i_IobaseAddon + 4);
/* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
@@ -1433,7 +1327,7 @@ static void apci3120_interrupt_dma(int irq, void *d)
devpriv->ul_DmaBufferVirtual[devpriv->
ui_DmaActualBuffer], samplesinbuf);
- if (!(cmd->flags & TRIG_WAKE_EOS)) {
+ if (!(cmd->flags & CMDF_WAKE_EOS)) {
s->async->events |= COMEDI_CB_EOS;
comedi_event(dev, s);
}
@@ -1450,10 +1344,10 @@ static void apci3120_interrupt_dma(int irq, void *d)
if (devpriv->b_DmaDoubleBuffer) { /* switch dma buffers */
devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
} else {
-/*
- * restart DMA if is not used double buffering
- * ADDED REINITIALISE THE DMA
- */
+ /*
+ * restart DMA if is not used double buffering
+ * ADDED REINITIALISE THE DMA
+ */
ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
@@ -1462,11 +1356,11 @@ static void apci3120_interrupt_dma(int irq, void *d)
outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
devpriv->i_IobaseAddon + 2);
outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
- outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2); /* */
-/*
- * A2P FIFO MANAGEMENT
- * A2P fifo reset & transfer control enable
- */
+ outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2);
+ /*
+ * A2P FIFO MANAGEMENT
+ * A2P fifo reset & transfer control enable
+ */
outl(APCI3120_A2P_FIFO_MANAGEMENT,
devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
@@ -1488,11 +1382,11 @@ static void apci3120_interrupt_dma(int irq, void *d)
outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
outw(high_word, devpriv->i_IobaseAddon + 2);
-/*
- * To configure A2P FIFO
- * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
- * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
- */
+ /*
+ * To configure A2P FIFO
+ * ENABLE A2P FIFO WRITE AND ENABLE AMWEN
+ * AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
+ */
outw(3, devpriv->i_IobaseAddon + 4);
/* initialise end of dma interrupt AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI) */
outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
@@ -1570,7 +1464,6 @@ static void apci3120_interrupt(int irq, void *d)
if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
/* Read the AI Value */
-
devpriv->ui_AiReadData[0] =
(unsigned int) inw(devpriv->iobase + 0);
devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
@@ -1670,7 +1563,6 @@ static void apci3120_interrupt(int irq, void *d)
default:
/* disable Timer Interrupt */
-
devpriv->b_ModeSelectRegister =
devpriv->
b_ModeSelectRegister &
@@ -1688,17 +1580,12 @@ static void apci3120_interrupt(int irq, void *d)
if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
if (devpriv->ai_running) {
- /****************************/
/* Clear Timer Write TC int */
- /****************************/
-
outl(APCI3120_CLEAR_WRITE_TC_INT,
devpriv->i_IobaseAmcc +
APCI3120_AMCC_OP_REG_INTCSR);
- /************************************/
/* Clears the timer status register */
- /************************************/
inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
/* do some data transfer */
apci3120_interrupt_dma(irq, d);
@@ -1711,8 +1598,6 @@ static void apci3120_interrupt(int irq, void *d)
}
}
-
- return;
}
/*
@@ -1728,7 +1613,7 @@ static int apci3120_config_insn_timer(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
struct addi_private *devpriv = dev->private;
unsigned int ui_Timervalue2;
unsigned short us_TmpValue;
@@ -1741,13 +1626,12 @@ static int apci3120_config_insn_timer(struct comedi_device *dev,
ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */
- /* this_board->timer_config(dev, ui_Timervalue2,(unsigned char)data[0]); */
us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
-/*
- * EL250804: Testing if board APCI3120 have the new Quartz or if it
- * is an APCI3001 and calculate the time value to set in the timer
- */
+ /*
+ * EL250804: Testing if board APCI3120 have the new Quartz or if it
+ * is an APCI3001 and calculate the time value to set in the timer
+ */
if ((us_TmpValue & 0x00B0) == 0x00B0
|| !strcmp(this_board->pc_DriverName, "apci3001")) {
/* Calculate the time value to set in the timer */
@@ -1775,11 +1659,6 @@ static int apci3120_config_insn_timer(struct comedi_device *dev,
outb(devpriv->b_ModeSelectRegister,
devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
if (data[0] == APCI3120_TIMER) { /* initialize timer */
- /* devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister |
- * APCI3120_ENABLE_TIMER_INT; */
-
- /* outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT); */
-
/* Set the Timer 2 in mode 2(Timer) */
devpriv->b_TimerSelectMode =
(devpriv->
@@ -1787,13 +1666,13 @@ static int apci3120_config_insn_timer(struct comedi_device *dev,
outb(devpriv->b_TimerSelectMode,
devpriv->iobase + APCI3120_TIMER_CRT1);
-/*
- * Configure the timer 2 for writing the LOW unsigned short of timer
- * is Delay value You must make a b_tmp variable with
- * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
- * you can set the digital output and configure the timer 2,and if
- * you don't make this, digital output are erase (Set to 0)
- */
+ /*
+ * Configure the timer 2 for writing the LOW unsigned short of timer
+ * is Delay value You must make a b_tmp variable with
+ * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
+ * you can set the digital output and configure the timer 2,and if
+ * you don't make this, digital output are erase (Set to 0)
+ */
/* Writing LOW unsigned short */
b_Tmp = ((devpriv->
@@ -1816,20 +1695,19 @@ static int apci3120_config_insn_timer(struct comedi_device *dev,
} else { /* Initialize Watch dog */
/* Set the Timer 2 in mode 5(Watchdog) */
-
devpriv->b_TimerSelectMode =
(devpriv->
b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
outb(devpriv->b_TimerSelectMode,
devpriv->iobase + APCI3120_TIMER_CRT1);
-/*
- * Configure the timer 2 for writing the LOW unsigned short of timer
- * is Delay value You must make a b_tmp variable with
- * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
- * you can set the digital output and configure the timer 2,and if
- * you don't make this, digital output are erase (Set to 0)
- */
+ /*
+ * Configure the timer 2 for writing the LOW unsigned short of timer
+ * is Delay value You must make a b_tmp variable with
+ * DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
+ * you can set the digital output and configure the timer 2,and if
+ * you don't make this, digital output are erase (Set to 0)
+ */
/* Writing LOW unsigned short */
b_Tmp = ((devpriv->
@@ -1873,7 +1751,7 @@ static int apci3120_write_insn_timer(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
struct addi_private *devpriv = dev->private;
unsigned int ui_Timervalue2 = 0;
unsigned short us_TmpValue;
@@ -1898,8 +1776,6 @@ static int apci3120_write_insn_timer(struct comedi_device *dev,
ui_Timervalue2 = 0;
}
- /* this_board->timer_write(dev,data[0],ui_Timervalue2); */
-
switch (data[0]) {
case APCI3120_START:
@@ -1937,7 +1813,7 @@ static int apci3120_write_insn_timer(struct comedi_device *dev,
devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* start timer */
- /* For Timer mode is Gate2 must be activated **timer started */
+ /* For Timer mode is Gate2 must be activated timer started */
devpriv->us_OutputRegister =
devpriv->
us_OutputRegister | APCI3120_ENABLE_TIMER2;
@@ -1979,9 +1855,6 @@ static int apci3120_write_insn_timer(struct comedi_device *dev,
/* Reset FC_TIMER BIT */
inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
- /* Disable timer */
- /* devpriv->b_Timer2Mode=APCI3120_DISABLE; */
-
break;
case 2: /* write new value to Timer */
@@ -1990,14 +1863,13 @@ static int apci3120_write_insn_timer(struct comedi_device *dev,
"timer2 not configured in TIMER MODE\n");
return -EINVAL;
}
- /* ui_Timervalue2=data[1]; // passed as argument */
us_TmpValue =
(unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
-/*
- * EL250804: Testing if board APCI3120 have the new Quartz or if it
- * is an APCI3001 and calculate the time value to set in the timer
- */
+ /*
+ * EL250804: Testing if board APCI3120 have the new Quartz or if it
+ * is an APCI3001 and calculate the time value to set in the timer
+ */
if ((us_TmpValue & 0x00B0) == 0x00B0
|| !strcmp(this_board->pc_DriverName, "apci3001")) {
/* Calculate the time value to set in the timer */
@@ -2053,8 +1925,6 @@ static int apci3120_read_insn_timer(struct comedi_device *dev,
&& (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
dev_err(dev->class_dev, "timer2 not configured\n");
}
-
- /* this_board->timer_read(dev,data); */
if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
/* Read the LOW unsigned short of Timer 2 register */
@@ -2137,7 +2007,6 @@ static int apci3120_ao_insn_write(struct comedi_device *dev,
ui_Range = CR_RANGE(insn->chanspec);
ui_Channel = CR_CHAN(insn->chanspec);
- /* this_board->ao_write(dev, ui_Range, ui_Channel,data[0]); */
if (ui_Range) { /* if 1 then unipolar */
if (data[0] != 0)
@@ -2163,17 +2032,17 @@ static int apci3120_ao_insn_write(struct comedi_device *dev,
} while (us_TmpValue != 0x0001);
if (ui_Channel <= 3)
-/*
- * for channel 0-3 out at the register 1 (wrDac1-8) data[i]
- * typecasted to ushort since word write is to be done
- */
+ /*
+ * for channel 0-3 out at the register 1 (wrDac1-8) data[i]
+ * typecasted to ushort since word write is to be done
+ */
outw((unsigned short) data[0],
devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
else
-/*
- * for channel 4-7 out at the register 2 (wrDac5-8) data[i]
- * typecasted to ushort since word write is to be done
- */
+ /*
+ * for channel 4-7 out at the register 2 (wrDac5-8) data[i]
+ * typecasted to ushort since word write is to be done
+ */
outw((unsigned short) data[0],
devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
index e82c3fcd048b..339519a3d6b5 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
@@ -168,7 +168,7 @@ static int apci3501_read_insn_timer(struct comedi_device *dev,
else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER)
&& (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG)) {
- printk("\nIn ReadTimerCounterWatchdog :: Invalid Subdevice \n");
+ dev_err(dev->class_dev, "Invalid subdevice.\n");
}
return insn->n;
}
diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c
index 1b2e7c040c9f..840cb289507a 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1032.c
@@ -190,9 +190,6 @@ static int apci1032_cos_cmdtest(struct comedi_device *dev,
/* Step 2a : make sure trigger sources are unique */
/* 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);
@@ -204,10 +201,9 @@ static int apci1032_cos_cmdtest(struct comedi_device *dev,
if (err)
return 3;
- /* step 4: ignored */
+ /* Step 4: fix up any arguments */
- if (err)
- return 4;
+ /* Step 5: check channel list if it exists */
return 0;
}
@@ -347,9 +343,7 @@ static void apci1032_detach(struct comedi_device *dev)
{
if (dev->iobase)
apci1032_reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver apci1032_driver = {
diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c
index e9c5291c77cd..55d00fd94c91 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1516.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1516.c
@@ -102,7 +102,7 @@ static int apci1516_do_insn_bits(struct comedi_device *dev,
static int apci1516_reset(struct comedi_device *dev)
{
- const struct apci1516_boardinfo *this_board = comedi_board(dev);
+ const struct apci1516_boardinfo *this_board = dev->board_ptr;
struct apci1516_private *devpriv = dev->private;
if (!this_board->has_wdog)
@@ -190,7 +190,7 @@ static void apci1516_detach(struct comedi_device *dev)
{
if (dev->iobase)
apci1516_reset(dev);
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver apci1516_driver = {
diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c
index 543cb074213a..688b015a834e 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1564.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1564.c
@@ -1,3 +1,26 @@
+/*
+ * addi_apci_1564.c
+ * 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 <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
@@ -42,10 +65,10 @@ static int apci1564_reset(struct comedi_device *dev)
outl(0x0, devpriv->amcc_iobase + 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));
+ outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER1));
+ outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER2));
+ outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER3));
+ outl(0x0, dev->iobase + APCI1564_COUNTER_CTRL_REG(APCI1564_COUNTER4));
return 0;
}
@@ -94,17 +117,20 @@ static irqreturn_t apci1564_interrupt(int irq, void *d)
}
for (chan = 0; chan < 4; chan++) {
- status = inl(dev->iobase + APCI1564_TCW_IRQ_REG(chan));
+ status = inl(dev->iobase + APCI1564_COUNTER_IRQ_REG(chan));
if (status & 0x01) {
/* Disable Counter Interrupt */
- ctrl = inl(dev->iobase + APCI1564_TCW_CTRL_REG(chan));
- outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(chan));
+ ctrl = inl(dev->iobase +
+ APCI1564_COUNTER_CTRL_REG(chan));
+ outl(0x0, dev->iobase +
+ APCI1564_COUNTER_CTRL_REG(chan));
/* Send a signal to from kernel to user space */
send_sig(SIGIO, devpriv->tsk_current, 0);
/* Enable Counter Interrupt */
- outl(ctrl, dev->iobase + APCI1564_TCW_CTRL_REG(chan));
+ outl(ctrl, dev->iobase +
+ APCI1564_COUNTER_CTRL_REG(chan));
}
}
@@ -282,9 +308,6 @@ static int apci1564_cos_cmdtest(struct comedi_device *dev,
/* Step 2a : make sure trigger sources are unique */
/* 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);
@@ -296,10 +319,9 @@ static int apci1564_cos_cmdtest(struct comedi_device *dev,
if (err)
return 3;
- /* step 4: ignored */
+ /* Step 4: fix up any arguments */
- if (err)
- return 4;
+ /* Step 5: check channel list if it exists */
return 0;
}
@@ -374,53 +396,52 @@ static int apci1564_auto_attach(struct comedi_device *dev,
/* 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->range_table = &range_digital;
- s->insn_bits = apci1564_di_insn_bits;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 32;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ 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 = 1;
- s->range_table = &range_digital;
- s->insn_config = apci1564_do_config;
- s->insn_bits = apci1564_do_insn_bits;
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 32;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = apci1564_do_insn_bits;
/* Change-Of-State (COS) interrupt subdevice */
s = &dev->subdevices[2];
if (dev->irq) {
dev->read_subdev = s;
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
- s->n_chan = 1;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->len_chanlist = 1;
- s->insn_config = apci1564_cos_insn_config;
- s->insn_bits = apci1564_cos_insn_bits;
- s->do_cmdtest = apci1564_cos_cmdtest;
- s->do_cmd = apci1564_cos_cmd;
- s->cancel = apci1564_cos_cancel;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
+ s->n_chan = 1;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->len_chanlist = 1;
+ s->insn_config = apci1564_cos_insn_config;
+ s->insn_bits = apci1564_cos_insn_bits;
+ s->do_cmdtest = apci1564_cos_cmdtest;
+ s->do_cmd = apci1564_cos_cmd;
+ s->cancel = apci1564_cos_cancel;
} else {
- s->type = COMEDI_SUBD_UNUSED;
+ s->type = COMEDI_SUBD_UNUSED;
}
/* Allocate and Initialise Timer Subdevice Structures */
s = &dev->subdevices[3];
- 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;
+ 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;
/* Initialize the watchdog subdevice */
s = &dev->subdevices[4];
@@ -430,12 +451,12 @@ static int apci1564_auto_attach(struct comedi_device *dev,
/* Initialize the diagnostic status subdevice */
s = &dev->subdevices[5];
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = 2;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = apci1564_diag_insn_bits;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 2;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = apci1564_diag_insn_bits;
return 0;
}
@@ -444,9 +465,7 @@ static void apci1564_detach(struct comedi_device *dev)
{
if (dev->iobase)
apci1564_reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver apci1564_driver = {
diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c
index 28df4b50b87a..4162e2dc2860 100644
--- a/drivers/staging/comedi/drivers/addi_apci_16xx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c
@@ -159,7 +159,7 @@ static struct comedi_driver apci16xx_driver = {
.driver_name = "addi_apci_16xx",
.module = THIS_MODULE,
.auto_attach = apci16xx_auto_attach,
- .detach = comedi_pci_disable,
+ .detach = comedi_pci_detach,
};
static int apci16xx_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c
index be0a8a7bd3b2..aea3da325359 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2032.c
@@ -86,30 +86,6 @@ static void apci2032_int_stop(struct comedi_device *dev,
outl(0x0, dev->iobase + APCI2032_INT_CTRL_REG);
}
-static bool apci2032_int_start(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned char enabled_isns)
-{
- struct apci2032_int_private *subpriv = s->private;
- struct comedi_cmd *cmd = &s->async->cmd;
- bool do_event;
-
- subpriv->enabled_isns = enabled_isns;
- subpriv->stop_count = cmd->stop_arg;
- if (cmd->stop_src == TRIG_COUNT && subpriv->stop_count == 0) {
- /* An empty acquisition! */
- s->async->events |= COMEDI_CB_EOA;
- subpriv->active = false;
- do_event = true;
- } else {
- subpriv->active = true;
- outl(enabled_isns, dev->iobase + APCI2032_INT_CTRL_REG);
- do_event = false;
- }
-
- return do_event;
-}
-
static int apci2032_int_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
@@ -141,16 +117,17 @@ static int apci2032_int_cmdtest(struct comedi_device *dev,
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, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_NONE)
+ 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: ignored */
+ /* Step 4: fix up any arguments */
- if (err)
- return 4;
+ /* Step 5: check channel list if it exists */
return 0;
}
@@ -163,18 +140,19 @@ static int apci2032_int_cmd(struct comedi_device *dev,
unsigned char enabled_isns;
unsigned int n;
unsigned long flags;
- bool do_event;
enabled_isns = 0;
for (n = 0; n < cmd->chanlist_len; n++)
enabled_isns |= 1 << CR_CHAN(cmd->chanlist[n]);
spin_lock_irqsave(&subpriv->spinlock, flags);
- do_event = apci2032_int_start(dev, s, enabled_isns);
- spin_unlock_irqrestore(&subpriv->spinlock, flags);
- if (do_event)
- comedi_event(dev, s);
+ subpriv->enabled_isns = enabled_isns;
+ subpriv->stop_count = cmd->stop_arg;
+ subpriv->active = true;
+ outl(enabled_isns, dev->iobase + APCI2032_INT_CTRL_REG);
+
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
return 0;
}
@@ -339,11 +317,9 @@ static void apci2032_detach(struct comedi_device *dev)
{
if (dev->iobase)
apci2032_reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
+ comedi_pci_detach(dev);
if (dev->read_subdev)
kfree(dev->read_subdev->private);
- comedi_pci_disable(dev);
}
static struct comedi_driver apci2032_driver = {
diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c
index e1a916546d18..51ab1f937bae 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2200.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2200.c
@@ -118,7 +118,7 @@ static void apci2200_detach(struct comedi_device *dev)
{
if (dev->iobase)
apci2200_reset(dev);
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver apci2200_driver = {
diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c
index 0b77f1012d47..ba71e24a56fd 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3120.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3120.c
@@ -44,7 +44,7 @@ static const struct addi_board apci3120_boardtypes[] = {
static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
- const struct addi_board *this_board = comedi_board(dev);
+ const struct addi_board *this_board = dev->board_ptr;
this_board->interrupt(irq, d);
return IRQ_RETVAL(1);
@@ -57,7 +57,7 @@ static int apci3120_auto_attach(struct comedi_device *dev,
const struct addi_board *this_board = NULL;
struct addi_private *devpriv;
struct comedi_subdevice *s;
- int ret, pages, i;
+ int ret, order, i;
if (context < ARRAY_SIZE(apci3120_boardtypes))
this_board = &apci3120_boardtypes[context];
@@ -88,28 +88,23 @@ static int apci3120_auto_attach(struct comedi_device *dev,
dev->irq = pcidev->irq;
}
- devpriv->us_UseDma = 1;
-
/* Allocate DMA buffers */
- devpriv->b_DmaDoubleBuffer = 0;
for (i = 0; i < 2; i++) {
- for (pages = 4; pages >= 0; pages--) {
+ for (order = 2; order >= 0; order--) {
devpriv->ul_DmaBufferVirtual[i] =
- (void *) __get_free_pages(GFP_KERNEL, pages);
+ dma_alloc_coherent(dev->hw_dev, PAGE_SIZE << order,
+ &devpriv->ul_DmaBufferHw[i],
+ GFP_KERNEL);
if (devpriv->ul_DmaBufferVirtual[i])
break;
}
- if (devpriv->ul_DmaBufferVirtual[i]) {
- devpriv->ui_DmaBufferPages[i] = pages;
- devpriv->ui_DmaBufferSize[i] = PAGE_SIZE * pages;
- devpriv->ul_DmaBufferHw[i] =
- virt_to_bus((void *)devpriv->
- ul_DmaBufferVirtual[i]);
- }
+ if (!devpriv->ul_DmaBufferVirtual[i])
+ break;
+ devpriv->ui_DmaBufferSize[i] = PAGE_SIZE << order;
}
- if (!devpriv->ul_DmaBufferVirtual[0])
- devpriv->us_UseDma = 0;
+ if (devpriv->ul_DmaBufferVirtual[0])
+ devpriv->us_UseDma = 1;
if (devpriv->ul_DmaBufferVirtual[1])
devpriv->b_DmaDoubleBuffer = 1;
@@ -195,23 +190,22 @@ static void apci3120_detach(struct comedi_device *dev)
{
struct addi_private *devpriv = dev->private;
+ if (dev->iobase)
+ apci3120_reset(dev);
+ comedi_pci_detach(dev);
if (devpriv) {
- if (dev->iobase)
- apci3120_reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (devpriv->ul_DmaBufferVirtual[0]) {
- free_pages((unsigned long)devpriv->
- ul_DmaBufferVirtual[0],
- devpriv->ui_DmaBufferPages[0]);
- }
- if (devpriv->ul_DmaBufferVirtual[1]) {
- free_pages((unsigned long)devpriv->
- ul_DmaBufferVirtual[1],
- devpriv->ui_DmaBufferPages[1]);
+ unsigned int i;
+
+ for (i = 0; i < 2; i++) {
+ if (devpriv->ul_DmaBufferVirtual[i]) {
+ dma_free_coherent(dev->hw_dev,
+ devpriv->ui_DmaBufferSize[i],
+ devpriv->
+ ul_DmaBufferVirtual[i],
+ devpriv->ul_DmaBufferHw[i]);
+ }
}
}
- comedi_pci_disable(dev);
}
static struct comedi_driver apci3120_driver = {
diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c
index d9594f48d00f..010efa3fed6c 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3501.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3501.c
@@ -104,9 +104,9 @@ static int apci3501_ao_insn_write(struct comedi_device *dev,
{
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int range = CR_RANGE(insn->chanspec);
- unsigned int val = 0;
- int i;
+ unsigned int cfg = APCI3501_AO_DATA_CHAN(chan);
int ret;
+ int i;
/*
* All analog output channels have the same output range.
@@ -117,14 +117,14 @@ static int apci3501_ao_insn_write(struct comedi_device *dev,
if (range) {
outl(0, dev->iobase + APCI3501_AO_CTRL_STATUS_REG);
} else {
- val |= APCI3501_AO_DATA_BIPOLAR;
+ cfg |= APCI3501_AO_DATA_BIPOLAR;
outl(APCI3501_AO_CTRL_BIPOLAR,
dev->iobase + APCI3501_AO_CTRL_STATUS_REG);
}
- val |= APCI3501_AO_DATA_CHAN(chan);
-
for (i = 0; i < insn->n; i++) {
+ unsigned int val = data[i];
+
if (range == 1) {
if (data[i] > 0x1fff) {
dev_err(dev->class_dev,
@@ -137,8 +137,10 @@ static int apci3501_ao_insn_write(struct comedi_device *dev,
if (ret)
return ret;
- outl(val | APCI3501_AO_DATA_VAL(data[i]),
+ outl(cfg | APCI3501_AO_DATA_VAL(val),
dev->iobase + APCI3501_AO_DATA_REG);
+
+ s->readback[chan] = val;
}
return insn->n;
@@ -360,6 +362,11 @@ static int apci3501_auto_attach(struct comedi_device *dev,
s->maxdata = 0x3fff;
s->range_table = &apci3501_ao_range;
s->insn_write = apci3501_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -410,9 +417,7 @@ static void apci3501_detach(struct comedi_device *dev)
{
if (dev->iobase)
apci3501_reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver apci3501_driver = {
diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
index 0f0c7fa5daa3..a296bd5b2c0c 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
@@ -472,7 +472,7 @@ static int apci3xxx_ai_insn_read(struct comedi_device *dev,
static int apci3xxx_ai_ns_to_timer(struct comedi_device *dev,
unsigned int *ns, unsigned int flags)
{
- const struct apci3xxx_boardinfo *board = comedi_board(dev);
+ const struct apci3xxx_boardinfo *board = dev->board_ptr;
struct apci3xxx_private *devpriv = dev->private;
unsigned int base;
unsigned int timer;
@@ -496,15 +496,15 @@ static int apci3xxx_ai_ns_to_timer(struct comedi_device *dev,
break;
}
- switch (flags & TRIG_ROUND_MASK) {
- case TRIG_ROUND_NEAREST:
+ switch (flags & CMDF_ROUND_MASK) {
+ case CMDF_ROUND_NEAREST:
default:
timer = (*ns + base / 2) / base;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
timer = *ns / base;
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
timer = (*ns + base - 1) / base;
break;
}
@@ -523,7 +523,7 @@ static int apci3xxx_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct apci3xxx_boardinfo *board = comedi_board(dev);
+ const struct apci3xxx_boardinfo *board = dev->board_ptr;
int err = 0;
unsigned int arg;
@@ -628,16 +628,20 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev,
int i;
for (i = 0; i < insn->n; i++) {
+ unsigned int val = data[i];
+
/* Set the range selection */
writel(range, dev->mmio + 96);
/* Write the analog value to the selected channel */
- writel((data[i] << 8) | chan, dev->mmio + 100);
+ writel((val << 8) | chan, dev->mmio + 100);
/* Wait the end of transfer */
ret = comedi_timeout(dev, s, insn, apci3xxx_ao_eoc, 0);
if (ret)
return ret;
+
+ s->readback[chan] = val;
}
return insn->n;
@@ -850,6 +854,11 @@ static int apci3xxx_auto_attach(struct comedi_device *dev,
s->maxdata = 0x0fff;
s->range_table = &apci3xxx_ao_range;
s->insn_write = apci3xxx_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
subdev++;
}
@@ -901,17 +910,9 @@ static int apci3xxx_auto_attach(struct comedi_device *dev,
static void apci3xxx_detach(struct comedi_device *dev)
{
- struct apci3xxx_private *devpriv = dev->private;
-
- if (devpriv) {
- if (dev->iobase)
- apci3xxx_reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->mmio)
- iounmap(dev->mmio);
- }
- comedi_pci_disable(dev);
+ if (dev->iobase)
+ apci3xxx_reset(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver apci3xxx_driver = {
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index 921f6942dfce..0ad46fe492c9 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -46,8 +46,6 @@
#define PCI6208_DIO_DI_MASK (0xf0)
#define PCI6208_DIO_DI_SHIFT (4)
-#define PCI6208_MAX_AO_CHANNELS 16
-
enum pci6208_boardid {
BOARD_PCI6208,
BOARD_PCI6216,
@@ -69,10 +67,6 @@ static const struct pci6208_board pci6208_boards[] = {
},
};
-struct pci6208_private {
- unsigned int ao_readback[PCI6208_MAX_AO_CHANNELS];
-};
-
static int pci6208_ao_eoc(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -91,9 +85,8 @@ static int pci6208_ao_insn_write(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- struct pci6208_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int val = devpriv->ao_readback[chan];
+ unsigned int val = s->readback[chan];
int ret;
int i;
@@ -108,23 +101,9 @@ static int pci6208_ao_insn_write(struct comedi_device *dev,
/* the hardware expects two's complement values */
outw(comedi_offset_munge(s, val),
dev->iobase + PCI6208_AO_CONTROL(chan));
- }
- devpriv->ao_readback[chan] = val;
-
- return insn->n;
-}
-static int pci6208_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct pci6208_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];
+ s->readback[chan] = val;
+ }
return insn->n;
}
@@ -162,7 +141,6 @@ static int pci6208_auto_attach(struct comedi_device *dev,
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
const struct pci6208_board *boardinfo = NULL;
- struct pci6208_private *devpriv;
struct comedi_subdevice *s;
unsigned int val;
int ret;
@@ -174,10 +152,6 @@ static int pci6208_auto_attach(struct comedi_device *dev,
dev->board_ptr = boardinfo;
dev->board_name = boardinfo->name;
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
ret = comedi_pci_enable(dev);
if (ret)
return ret;
@@ -195,7 +169,11 @@ static int pci6208_auto_attach(struct comedi_device *dev,
s->maxdata = 0xffff;
s->range_table = &range_bipolar10;
s->insn_write = pci6208_ao_insn_write;
- s->insn_read = pci6208_ao_insn_read;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[1];
/* digital input subdevice */
@@ -230,7 +208,7 @@ static struct comedi_driver adl_pci6208_driver = {
.driver_name = "adl_pci6208",
.module = THIS_MODULE,
.auto_attach = pci6208_auto_attach,
- .detach = comedi_pci_disable,
+ .detach = comedi_pci_detach,
};
static int adl_pci6208_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c
index 5e3cc77a8a0c..fb8e5f582496 100644
--- a/drivers/staging/comedi/drivers/adl_pci7x3x.c
+++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c
@@ -246,7 +246,7 @@ static struct comedi_driver adl_pci7x3x_driver = {
.driver_name = "adl_pci7x3x",
.module = THIS_MODULE,
.auto_attach = adl_pci7x3x_auto_attach,
- .detach = comedi_pci_disable,
+ .detach = comedi_pci_detach,
};
static int adl_pci7x3x_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c
index 300df55a2802..72bccb447a74 100644
--- a/drivers/staging/comedi/drivers/adl_pci8164.c
+++ b/drivers/staging/comedi/drivers/adl_pci8164.c
@@ -135,7 +135,7 @@ static struct comedi_driver adl_pci8164_driver = {
.driver_name = "adl_pci8164",
.module = THIS_MODULE,
.auto_attach = adl_pci8164_auto_attach,
- .detach = comedi_pci_disable,
+ .detach = comedi_pci_detach,
};
static int adl_pci8164_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index 51edfebb952a..d18d8f21af23 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -139,8 +139,6 @@ struct pci9111_private_data {
unsigned int chunk_counter;
unsigned int chunk_num_samples;
- int ao_readback;
-
unsigned int div1;
unsigned int div2;
@@ -643,29 +641,15 @@ static int pci9111_ao_insn_write(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- struct pci9111_private_data *dev_private = dev->private;
- unsigned int val = 0;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = s->readback[chan];
int i;
for (i = 0; i < insn->n; i++) {
val = data[i];
outw(val, dev->iobase + PCI9111_AO_REG);
}
- dev_private->ao_readback = val;
-
- return insn->n;
-}
-
-static int pci9111_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct pci9111_private_data *dev_private = dev->private;
- int i;
-
- for (i = 0; i < insn->n; i++)
- data[i] = dev_private->ao_readback;
+ s->readback[chan] = val;
return insn->n;
}
@@ -768,7 +752,11 @@ static int pci9111_auto_attach(struct comedi_device *dev,
s->len_chanlist = 1;
s->range_table = &range_bipolar10;
s->insn_write = pci9111_ao_insn_write;
- s->insn_read = pci9111_ao_insn_read;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[2];
s->type = COMEDI_SUBD_DI;
@@ -793,9 +781,7 @@ static void pci9111_detach(struct comedi_device *dev)
{
if (dev->iobase)
pci9111_reset(dev);
- if (dev->irq != 0)
- free_irq(dev->irq, dev);
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver adl_pci9111_driver = {
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index f30b84e1987b..e18fd9569a2b 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -36,8 +36,8 @@
* b) DMA transfers must have the length aligned to two samples (32 bit),
* so there is some problems if cmd->chanlist_len is odd. This driver tries
* bypass this with adding one sample to the end of the every scan and discard
- * it on output but this cann't be used if cmd->scan_begin_src=TRIG_FOLLOW
- * and is used flag TRIG_WAKE_EOS, then driver switch to interrupt driven mode
+ * it on output but this can't be used if cmd->scan_begin_src=TRIG_FOLLOW
+ * and is used flag CMDF_WAKE_EOS, then driver switch to interrupt driven mode
* with interrupt after every sample.
* c) If isn't used DMA then you can use only mode where
* cmd->scan_begin_src=TRIG_FOLLOW.
@@ -49,19 +49,13 @@
* card will be used.
* [2] - 0= standard 8 DIFF/16 SE channels configuration
* n = external multiplexer connected, 1 <= n <= 256
- * [3] - 0=autoselect DMA or EOC interrupts operation
- * 1 = disable DMA mode
- * 3 = disable DMA and INT, only insn interface will work
+ * [3] - ignored
* [4] - sample&hold signal - card can generate signal for external S&H board
* 0 = use SSHO(pin 45) signal is generated in onboard hardware S&H logic
* 0 != use ADCHN7(pin 23) signal is generated from driver, number say how
* long delay is requested in ns and sign polarity of the hold
* (in this case external multiplexor can serve only 128 channels)
- * [5] - 0=stop measure on all hardware errors
- * 2 | = ignore ADOR - A/D Overrun status
- * 8|=ignore Bover - A/D Burst Mode Overrun status
- * 256|=ignore nFull - A/D FIFO Full status
- *
+ * [5] - ignored
*/
/*
@@ -91,111 +85,68 @@
#include "8253.h"
#include "comedi_fc.h"
-/* paranoid checks are broken */
-#undef PCI9118_PARANOIDCHECK /*
- * if defined, then is used code which control
- * correct channel number on every 12 bit sample
- */
-
#define IORANGE_9118 64 /* I hope */
#define PCI9118_CHANLEN 255 /*
* len of chanlist, some source say 256,
* but reality looks like 255 :-(
*/
-#define PCI9118_CNT0 0x00 /* R/W: 8254 counter 0 */
-#define PCI9118_CNT1 0x04 /* R/W: 8254 counter 0 */
-#define PCI9118_CNT2 0x08 /* R/W: 8254 counter 0 */
-#define PCI9118_CNTCTRL 0x0c /* W: 8254 counter control */
-#define PCI9118_AD_DATA 0x10 /* R: A/D data */
-#define PCI9118_DA1 0x10 /* W: D/A registers */
-#define PCI9118_DA2 0x14
-#define PCI9118_ADSTAT 0x18 /* R: A/D status register */
-#define PCI9118_ADCNTRL 0x18 /* W: A/D control register */
-#define PCI9118_DI 0x1c /* R: digi input register */
-#define PCI9118_DO 0x1c /* W: digi output register */
-#define PCI9118_SOFTTRG 0x20 /* W: soft trigger for A/D */
-#define PCI9118_GAIN 0x24 /* W: A/D gain/channel register */
-#define PCI9118_BURST 0x28 /* W: A/D burst number register */
-#define PCI9118_SCANMOD 0x2c /* W: A/D auto scan mode */
-#define PCI9118_ADFUNC 0x30 /* W: A/D function register */
-#define PCI9118_DELFIFO 0x34 /* W: A/D data FIFO reset */
-#define PCI9118_INTSRC 0x38 /* R: interrupt reason register */
-#define PCI9118_INTCTRL 0x38 /* W: interrupt control register */
-
-/* bits from A/D control register (PCI9118_ADCNTRL) */
-#define AdControl_UniP 0x80 /* 1=bipolar, 0=unipolar */
-#define AdControl_Diff 0x40 /* 1=differential, 0= single end inputs */
-#define AdControl_SoftG 0x20 /* 1=8254 counter works, 0=counter stops */
-#define AdControl_ExtG 0x10 /*
- * 1=8254 countrol controlled by TGIN(pin 46),
- * 0=controlled by SoftG
- */
-#define AdControl_ExtM 0x08 /*
- * 1=external hardware trigger (pin 44),
- * 0=internal trigger
- */
-#define AdControl_TmrTr 0x04 /*
- * 1=8254 is iternal trigger source,
- * 0=software trigger is source
- * (register PCI9118_SOFTTRG)
- */
-#define AdControl_Int 0x02 /* 1=enable INT, 0=disable */
-#define AdControl_Dma 0x01 /* 1=enable DMA, 0=disable */
-
-/* bits from A/D function register (PCI9118_ADFUNC) */
-#define AdFunction_PDTrg 0x80 /*
- * 1=positive,
- * 0=negative digital trigger
- * (only positive is correct)
- */
-#define AdFunction_PETrg 0x40 /*
- * 1=positive,
- * 0=negative external trigger
- * (only positive is correct)
- */
-#define AdFunction_BSSH 0x20 /* 1=with sample&hold, 0=without */
-#define AdFunction_BM 0x10 /* 1=burst mode, 0=normal mode */
-#define AdFunction_BS 0x08 /*
- * 1=burst mode start,
- * 0=burst mode stop
- */
-#define AdFunction_PM 0x04 /*
- * 1=post trigger mode,
- * 0=not post trigger
- */
-#define AdFunction_AM 0x02 /*
- * 1=about trigger mode,
- * 0=not about trigger
- */
-#define AdFunction_Start 0x01 /* 1=trigger start, 0=trigger stop */
-
-/* bits from A/D status register (PCI9118_ADSTAT) */
-#define AdStatus_nFull 0x100 /* 0=FIFO full (fatal), 1=not full */
-#define AdStatus_nHfull 0x080 /* 0=FIFO half full, 1=FIFO not half full */
-#define AdStatus_nEpty 0x040 /* 0=FIFO empty, 1=FIFO not empty */
-#define AdStatus_Acmp 0x020 /* */
-#define AdStatus_DTH 0x010 /* 1=external digital trigger */
-#define AdStatus_Bover 0x008 /* 1=burst mode overrun (fatal) */
-#define AdStatus_ADOS 0x004 /* 1=A/D over speed (warning) */
-#define AdStatus_ADOR 0x002 /* 1=A/D overrun (fatal) */
-#define AdStatus_ADrdy 0x001 /* 1=A/D already ready, 0=not ready */
-
-/* bits for interrupt reason and control (PCI9118_INTSRC, PCI9118_INTCTRL) */
-/* 1=interrupt occur, enable source, 0=interrupt not occur, disable source */
-#define Int_Timer 0x08 /* timer interrupt */
-#define Int_About 0x04 /* about trigger complete */
-#define Int_Hfull 0x02 /* A/D FIFO hlaf full */
-#define Int_DTrg 0x01 /* external digital trigger */
+/*
+ * PCI BAR2 Register map (dev->iobase)
+ */
+#define PCI9118_TIMER_REG(x) (0x00 + ((x) * 4))
+#define PCI9118_TIMER_CTRL_REG 0x0c
+#define PCI9118_AI_FIFO_REG 0x10
+#define PCI9118_AO_REG(x) (0x10 + ((x) * 4))
+#define PCI9118_AI_STATUS_REG 0x18
+#define PCI9118_AI_STATUS_NFULL (1 << 8) /* 0=FIFO full (fatal) */
+#define PCI9118_AI_STATUS_NHFULL (1 << 7) /* 0=FIFO half full */
+#define PCI9118_AI_STATUS_NEPTY (1 << 6) /* 0=FIFO empty */
+#define PCI9118_AI_STATUS_ACMP (1 << 5) /* 1=about trigger complete */
+#define PCI9118_AI_STATUS_DTH (1 << 4) /* 1=ext. digital trigger */
+#define PCI9118_AI_STATUS_BOVER (1 << 3) /* 1=burst overrun (fatal) */
+#define PCI9118_AI_STATUS_ADOS (1 << 2) /* 1=A/D over speed (warn) */
+#define PCI9118_AI_STATUS_ADOR (1 << 1) /* 1=A/D overrun (fatal) */
+#define PCI9118_AI_STATUS_ADRDY (1 << 0) /* 1=A/D ready */
+#define PCI9118_AI_CTRL_REG 0x18
+#define PCI9118_AI_CTRL_UNIP (1 << 7) /* 1=unipolar */
+#define PCI9118_AI_CTRL_DIFF (1 << 6) /* 1=differential inputs */
+#define PCI9118_AI_CTRL_SOFTG (1 << 5) /* 1=8254 software gate */
+#define PCI9118_AI_CTRL_EXTG (1 << 4) /* 1=8254 TGIN(pin 46) gate */
+#define PCI9118_AI_CTRL_EXTM (1 << 3) /* 1=ext. trigger (pin 44) */
+#define PCI9118_AI_CTRL_TMRTR (1 << 2) /* 1=8254 is trigger source */
+#define PCI9118_AI_CTRL_INT (1 << 1) /* 1=enable interrupt */
+#define PCI9118_AI_CTRL_DMA (1 << 0) /* 1=enable DMA */
+#define PCI9118_DIO_REG 0x1c
+#define PCI9118_SOFTTRG_REG 0x20
+#define PCI9118_AI_CHANLIST_REG 0x24
+#define PCI9118_AI_CHANLIST_RANGE(x) (((x) & 0x3) << 8)
+#define PCI9118_AI_CHANLIST_CHAN(x) ((x) << 0)
+#define PCI9118_AI_BURST_NUM_REG 0x28
+#define PCI9118_AI_AUTOSCAN_MODE_REG 0x2c
+#define PCI9118_AI_CFG_REG 0x30
+#define PCI9118_AI_CFG_PDTRG (1 << 7) /* 1=positive trigger */
+#define PCI9118_AI_CFG_PETRG (1 << 6) /* 1=positive ext. trigger */
+#define PCI9118_AI_CFG_BSSH (1 << 5) /* 1=with sample & hold */
+#define PCI9118_AI_CFG_BM (1 << 4) /* 1=burst mode */
+#define PCI9118_AI_CFG_BS (1 << 3) /* 1=burst mode start */
+#define PCI9118_AI_CFG_PM (1 << 2) /* 1=post trigger */
+#define PCI9118_AI_CFG_AM (1 << 1) /* 1=about trigger */
+#define PCI9118_AI_CFG_START (1 << 0) /* 1=trigger start */
+#define PCI9118_FIFO_RESET_REG 0x34
+#define PCI9118_INT_CTRL_REG 0x38
+#define PCI9118_INT_CTRL_TIMER (1 << 3) /* timer interrupt */
+#define PCI9118_INT_CTRL_ABOUT (1 << 2) /* about trigger complete */
+#define PCI9118_INT_CTRL_HFULL (1 << 1) /* A/D FIFO half full */
+#define PCI9118_INT_CTRL_DTRG (1 << 0) /* ext. digital trigger */
#define START_AI_EXT 0x01 /* start measure on external trigger */
#define STOP_AI_EXT 0x02 /* stop measure on external trigger */
-#define START_AI_INT 0x04 /* start measure on internal trigger */
#define STOP_AI_INT 0x08 /* stop measure on internal trigger */
-#define EXTTRG_AI 0 /* ext trg is used by AI */
+#define PCI9118_HALF_FIFO_SZ (1024 / 2)
-static const struct comedi_lrange range_pci9118dg_hr = {
+static const struct comedi_lrange pci9118_ai_range = {
8, {
BIP_RANGE(5),
BIP_RANGE(2.5),
@@ -208,7 +159,7 @@ static const struct comedi_lrange range_pci9118dg_hr = {
}
};
-static const struct comedi_lrange range_pci9118hg = {
+static const struct comedi_lrange pci9118hg_ai_range = {
8, {
BIP_RANGE(5),
BIP_RANGE(0.5),
@@ -226,102 +177,49 @@ static const struct comedi_lrange range_pci9118hg = {
* of BIP/UNI ranges
*/
-struct boardtype {
- const char *name; /* board name */
- int device_id; /* PCI device ID of card */
- int iorange_amcc; /* iorange for own S5933 region */
- int iorange_9118; /* pass thru card region size */
- int n_aichan; /* num of A/D chans */
- int n_aichand; /* num of A/D chans in diff mode */
- int mux_aichan; /*
- * num of A/D chans with
- * external multiplexor
- */
- int n_aichanlist; /* len of chanlist */
- int n_aochan; /* num of D/A chans */
- int ai_maxdata; /* resolution of A/D */
- int ao_maxdata; /* resolution of D/A */
- const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
- const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
- unsigned int ai_ns_min; /* max sample speed of card v ns */
- unsigned int ai_pacer_min; /*
- * minimal pacer value
- * (c1*c2 or c1 in burst)
- */
- int half_fifo_size; /* size of FIFO/2 */
+enum pci9118_boardid {
+ BOARD_PCI9118DG,
+ BOARD_PCI9118HG,
+ BOARD_PCI9118HR,
+};
+struct pci9118_boardinfo {
+ const char *name;
+ unsigned int ai_is_16bit:1;
+ unsigned int is_hg:1;
};
-static const struct boardtype boardtypes[] = {
- {
+static const struct pci9118_boardinfo pci9118_boards[] = {
+ [BOARD_PCI9118DG] = {
.name = "pci9118dg",
- .device_id = 0x80d9,
- .iorange_amcc = AMCC_OP_REG_SIZE,
- .iorange_9118 = IORANGE_9118,
- .n_aichan = 16,
- .n_aichand = 8,
- .mux_aichan = 256,
- .n_aichanlist = PCI9118_CHANLEN,
- .n_aochan = 2,
- .ai_maxdata = 0x0fff,
- .ao_maxdata = 0x0fff,
- .rangelist_ai = &range_pci9118dg_hr,
- .rangelist_ao = &range_bipolar10,
- .ai_ns_min = 3000,
- .ai_pacer_min = 12,
- .half_fifo_size = 512,
- }, {
+ },
+ [BOARD_PCI9118HG] = {
.name = "pci9118hg",
- .device_id = 0x80d9,
- .iorange_amcc = AMCC_OP_REG_SIZE,
- .iorange_9118 = IORANGE_9118,
- .n_aichan = 16,
- .n_aichand = 8,
- .mux_aichan = 256,
- .n_aichanlist = PCI9118_CHANLEN,
- .n_aochan = 2,
- .ai_maxdata = 0x0fff,
- .ao_maxdata = 0x0fff,
- .rangelist_ai = &range_pci9118hg,
- .rangelist_ao = &range_bipolar10,
- .ai_ns_min = 3000,
- .ai_pacer_min = 12,
- .half_fifo_size = 512,
- }, {
+ .is_hg = 1,
+ },
+ [BOARD_PCI9118HR] = {
.name = "pci9118hr",
- .device_id = 0x80d9,
- .iorange_amcc = AMCC_OP_REG_SIZE,
- .iorange_9118 = IORANGE_9118,
- .n_aichan = 16,
- .n_aichand = 8,
- .mux_aichan = 256,
- .n_aichanlist = PCI9118_CHANLEN,
- .n_aochan = 2,
- .ai_maxdata = 0xffff,
- .ao_maxdata = 0x0fff,
- .rangelist_ai = &range_pci9118dg_hr,
- .rangelist_ao = &range_bipolar10,
- .ai_ns_min = 10000,
- .ai_pacer_min = 40,
- .half_fifo_size = 512,
+ .ai_is_16bit = 1,
},
};
+struct pci9118_dmabuf {
+ unsigned short *virt; /* virtual address of buffer */
+ dma_addr_t hw; /* hardware (bus) address of buffer */
+ unsigned int size; /* size of dma buffer in bytes */
+ unsigned int use_size; /* which size we may now use for transfer */
+};
+
struct pci9118_private {
unsigned long iobase_a; /* base+size for AMCC chip */
- unsigned int master; /* master capable */
- unsigned int usemux; /* we want to use external multiplexor! */
-#ifdef PCI9118_PARANOIDCHECK
- unsigned short chanlist[PCI9118_CHANLEN + 1]; /*
- * list of
- * scanned channel
- */
- unsigned char chanlistlen; /* number of scanlist */
-#endif
- unsigned char AdControlReg; /* A/D control register */
- unsigned char IntControlReg; /* Interrupt control register */
- unsigned char AdFunctionReg; /* A/D function register */
- char ai_neverending; /* we do unlimited AI */
+ unsigned int master:1;
+ unsigned int dma_doublebuf:1;
+ unsigned int ai_neverending:1;
+ unsigned int usedma:1;
+ unsigned int usemux:1;
+ unsigned char ai_ctrl;
+ unsigned char int_ctrl;
+ unsigned char ai_cfg;
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_n_realscanlen; /*
@@ -346,29 +244,8 @@ struct pci9118_private {
* divisors for start of measure
* on external start
*/
- unsigned short ao_data[2]; /* data output buffer */
- char dma_doublebuf; /* use double buffering */
unsigned int dma_actbuf; /* which buffer is used now */
- unsigned short *dmabuf_virt[2]; /*
- * pointers to begin of
- * DMA buffer
- */
- unsigned long dmabuf_hw[2]; /* hw address of DMA buff */
- unsigned int dmabuf_size[2]; /*
- * size of dma buffer in bytes
- */
- unsigned int dmabuf_use_size[2]; /*
- * which size we may now use
- * for transfer
- */
- unsigned int dmabuf_used_size[2]; /* which size was truly used */
- unsigned int dmabuf_panic_size[2];
- int dmabuf_pages[2]; /* number of pages in buffer */
- unsigned char exttrg_users; /*
- * bit field of external trigger
- * users(0-AI, 1-AO, 2-DI, 3-DO)
- */
- unsigned char usedma; /* =1 use DMA transfer and not INT */
+ struct pci9118_dmabuf dmabuf[2];
int softsshdelay; /*
* >0 use software S&H,
* numer is requested delay in ns
@@ -381,15 +258,74 @@ struct pci9118_private {
* polarity of S&H signal
* in hold state
*/
- unsigned int ai_maskerr; /* which warning was printed */
- unsigned int ai_maskharderr; /* on which error bits stops */
+ unsigned int ai_ns_min;
};
+static void pci9118_amcc_setup_dma(struct comedi_device *dev, unsigned int buf)
+{
+ struct pci9118_private *devpriv = dev->private;
+ struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[buf];
+
+ /* set the master write address and transfer count */
+ outl(dmabuf->hw, devpriv->iobase_a + AMCC_OP_REG_MWAR);
+ outl(dmabuf->use_size, devpriv->iobase_a + AMCC_OP_REG_MWTC);
+}
+
+static void pci9118_amcc_dma_ena(struct comedi_device *dev, bool enable)
+{
+ struct pci9118_private *devpriv = dev->private;
+ unsigned int mcsr;
+
+ mcsr = inl(devpriv->iobase_a + AMCC_OP_REG_MCSR);
+ if (enable)
+ mcsr |= RESET_A2P_FLAGS | A2P_HI_PRIORITY | EN_A2P_TRANSFERS;
+ else
+ mcsr &= ~EN_A2P_TRANSFERS;
+ outl(mcsr, devpriv->iobase_a + AMCC_OP_REG_MCSR);
+}
+
+static void pci9118_amcc_int_ena(struct comedi_device *dev, bool enable)
+{
+ struct pci9118_private *devpriv = dev->private;
+ unsigned int intcsr;
+
+ /* enable/disable interrupt for AMCC Incoming Mailbox 4 (32-bit) */
+ intcsr = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR);
+ if (enable)
+ intcsr |= 0x1f00;
+ else
+ intcsr &= ~0x1f00;
+ outl(intcsr, devpriv->iobase_a + AMCC_OP_REG_INTCSR);
+}
+
+static void pci9118_timer_write(struct comedi_device *dev,
+ unsigned int timer, unsigned int val)
+{
+ outl(val & 0xff, dev->iobase + PCI9118_TIMER_REG(timer));
+ outl((val >> 8) & 0xff, dev->iobase + PCI9118_TIMER_REG(timer));
+}
+
+static void pci9118_timer_set_mode(struct comedi_device *dev,
+ unsigned int timer, unsigned int mode)
+{
+ unsigned int val;
+
+ val = timer << 6; /* select timer */
+ val |= 0x30; /* load low then high byte */
+ val |= mode; /* set timer mode and BCD|binary */
+ outl(val, dev->iobase + PCI9118_TIMER_CTRL_REG);
+}
+
+static void pci9118_ai_reset_fifo(struct comedi_device *dev)
+{
+ /* writing any value resets the A/D FIFO */
+ outl(0, dev->iobase + PCI9118_FIFO_RESET_REG);
+}
+
static int check_channel_list(struct comedi_device *dev,
struct comedi_subdevice *s, int n_chan,
unsigned int *chanlist, int frontadd, int backadd)
{
- const struct boardtype *this_board = comedi_board(dev);
struct pci9118_private *devpriv = dev->private;
unsigned int i, differencial = 0, bipolar = 0;
@@ -423,7 +359,7 @@ static int check_channel_list(struct comedi_device *dev,
return 0;
}
if (!devpriv->usemux && differencial &&
- (CR_CHAN(chanlist[i]) >= this_board->n_aichand)) {
+ (CR_CHAN(chanlist[i]) >= (s->n_chan / 2))) {
dev_err(dev->class_dev,
"AREF_DIFF is only available for the first 8 channels!\n");
return 0;
@@ -433,234 +369,82 @@ static int check_channel_list(struct comedi_device *dev,
return 1;
}
-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)
+static void pci9118_set_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ int n_chan, unsigned int *chanlist,
+ int frontadd, int backadd)
{
struct pci9118_private *devpriv = dev->private;
- unsigned int i, differencial = 0, bipolar = 0;
- unsigned int scanquad, gain, ssh = 0x00;
-
- if (usedma == 1) {
- rot = 8;
- usedma = 0;
- }
-
- if (CR_AREF(chanlist[0]) == AREF_DIFF)
- differencial = 1; /* all input must be diff */
- if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES)
- bipolar = 1; /* all input must be bipolar */
-
- /* All is ok, so we can setup channel/range list */
-
- if (!bipolar) {
- devpriv->AdControlReg |= AdControl_UniP;
- /* set unibipolar */
- } else {
- devpriv->AdControlReg &= ((~AdControl_UniP) & 0xff);
- /* enable bipolar */
- }
-
- if (differencial) {
- devpriv->AdControlReg |= AdControl_Diff;
- /* enable diff inputs */
- } else {
- devpriv->AdControlReg &= ((~AdControl_Diff) & 0xff);
- /* set single ended inputs */
- }
-
- outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
- /* setup mode */
+ unsigned int chan0 = CR_CHAN(chanlist[0]);
+ unsigned int range0 = CR_RANGE(chanlist[0]);
+ unsigned int aref0 = CR_AREF(chanlist[0]);
+ unsigned int ssh = 0x00;
+ unsigned int val;
+ int i;
- outl(2, dev->iobase + PCI9118_SCANMOD);
- /* gods know why this sequence! */
- outl(0, dev->iobase + PCI9118_SCANMOD);
- outl(1, dev->iobase + PCI9118_SCANMOD);
-
-#ifdef PCI9118_PARANOIDCHECK
- devpriv->chanlistlen = n_chan;
- for (i = 0; i < (PCI9118_CHANLEN + 1); i++)
- devpriv->chanlist[i] = 0x55aa;
-#endif
-
- if (frontadd) { /* insert channels for S&H */
+ /*
+ * Configure analog input based on the first chanlist entry.
+ * All entries are either unipolar or bipolar and single-ended
+ * or differential.
+ */
+ devpriv->ai_ctrl = 0;
+ if (comedi_range_is_unipolar(s, range0))
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_UNIP;
+ if (aref0 == AREF_DIFF)
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_DIFF;
+ outl(devpriv->ai_ctrl, dev->iobase + PCI9118_AI_CTRL_REG);
+
+ /* gods know why this sequence! */
+ outl(2, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+ outl(0, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+ outl(1, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+
+ /* insert channels for S&H */
+ if (frontadd) {
+ val = PCI9118_AI_CHANLIST_CHAN(chan0) |
+ PCI9118_AI_CHANLIST_RANGE(range0);
ssh = devpriv->softsshsample;
for (i = 0; i < frontadd; i++) {
- /* store range list to card */
- scanquad = CR_CHAN(chanlist[0]);
- /* get channel number; */
- gain = CR_RANGE(chanlist[0]);
- /* get gain number */
- scanquad |= ((gain & 0x03) << 8);
- outl(scanquad | ssh, dev->iobase + PCI9118_GAIN);
+ outl(val | ssh, dev->iobase + PCI9118_AI_CHANLIST_REG);
ssh = devpriv->softsshhold;
}
}
- for (i = 0; i < n_chan; i++) { /* store range list to card */
- scanquad = CR_CHAN(chanlist[i]); /* get channel number */
-#ifdef PCI9118_PARANOIDCHECK
- devpriv->chanlist[i ^ usedma] = (scanquad & 0xf) << rot;
-#endif
- gain = CR_RANGE(chanlist[i]); /* get gain number */
- scanquad |= ((gain & 0x03) << 8);
- outl(scanquad | ssh, dev->iobase + PCI9118_GAIN);
- }
+ /* store chanlist */
+ for (i = 0; i < n_chan; i++) {
+ unsigned int chan = CR_CHAN(chanlist[i]);
+ unsigned int range = CR_RANGE(chanlist[i]);
- if (backadd) { /* insert channels for fit onto 32bit DMA */
- for (i = 0; i < backadd; i++) { /* store range list to card */
- scanquad = CR_CHAN(chanlist[0]);
- /* get channel number */
- gain = CR_RANGE(chanlist[0]); /* get gain number */
- scanquad |= ((gain & 0x03) << 8);
- outl(scanquad | ssh, dev->iobase + PCI9118_GAIN);
- }
+ val = PCI9118_AI_CHANLIST_CHAN(chan) |
+ PCI9118_AI_CHANLIST_RANGE(range);
+ outl(val | ssh, dev->iobase + PCI9118_AI_CHANLIST_REG);
}
-#ifdef PCI9118_PARANOIDCHECK
- devpriv->chanlist[n_chan ^ usedma] = devpriv->chanlist[0 ^ usedma];
- /* for 32bit operations */
-#endif
- outl(0, dev->iobase + PCI9118_SCANMOD); /* close scan queue */
- /* udelay(100); important delay, or first sample will be crippled */
-
- 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 ret;
- int n;
-
- devpriv->AdControlReg = AdControl_Int & 0xff;
- devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg;
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
- /*
- * positive triggers, no S&H,
- * no burst, burst stop,
- * no post trigger,
- * no about trigger,
- * trigger stop
- */
- if (!setup_channel_list(dev, s, 1, &insn->chanspec, 0, 0, 0, 0))
- return -EINVAL;
-
- outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
-
- for (n = 0; n < insn->n; n++) {
- outw(0, dev->iobase + PCI9118_SOFTTRG); /* start conversion */
- udelay(2);
-
- ret = comedi_timeout(dev, s, insn, pci9118_ai_eoc, 0);
- if (ret) {
- outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
- return ret;
- }
-
- if (s->maxdata == 0xffff) {
- data[n] =
- (inl(dev->iobase +
- PCI9118_AD_DATA) & 0xffff) ^ 0x8000;
- } else {
- data[n] =
- (inw(dev->iobase + PCI9118_AD_DATA) >> 4) & 0xfff;
- }
- }
-
- outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
- return n;
-
-}
-
-static int pci9118_insn_write_ao(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct pci9118_private *devpriv = dev->private;
- int n, chanreg, ch;
-
- ch = CR_CHAN(insn->chanspec);
- if (ch)
- chanreg = PCI9118_DA2;
- else
- chanreg = PCI9118_DA1;
-
-
- for (n = 0; n < insn->n; n++) {
- outl(data[n], dev->iobase + chanreg);
- devpriv->ao_data[ch] = data[n];
+ /* insert channels to fit onto 32bit DMA */
+ if (backadd) {
+ val = PCI9118_AI_CHANLIST_CHAN(chan0) |
+ PCI9118_AI_CHANLIST_RANGE(range0);
+ for (i = 0; i < backadd; i++)
+ outl(val | ssh, dev->iobase + PCI9118_AI_CHANLIST_REG);
}
-
- return n;
-}
-
-static int pci9118_insn_read_ao(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct pci9118_private *devpriv = dev->private;
- int n, chan;
-
- chan = CR_CHAN(insn->chanspec);
- for (n = 0; n < insn->n; n++)
- data[n] = devpriv->ao_data[chan];
-
- return n;
-}
-
-static int pci9118_insn_bits_di(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- data[1] = inl(dev->iobase + PCI9118_DI) & 0xf;
-
- return insn->n;
-}
-
-static int pci9118_insn_bits_do(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- if (comedi_dio_update_state(s, data))
- outl(s->state & 0x0f, dev->iobase + PCI9118_DO);
-
- data[1] = s->state;
-
- return insn->n;
+ /* close scan queue */
+ outl(0, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+ /* udelay(100); important delay, or first sample will be crippled */
}
-static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev)
+static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev,
+ unsigned int next_buf)
{
struct pci9118_private *devpriv = dev->private;
-
- devpriv->AdFunctionReg =
- AdFunction_PDTrg | AdFunction_PETrg | AdFunction_AM;
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
- outl(0x30, dev->iobase + PCI9118_CNTCTRL);
- outl((devpriv->dmabuf_hw[1 - devpriv->dma_actbuf] >> 1) & 0xff,
- dev->iobase + PCI9118_CNT0);
- outl((devpriv->dmabuf_hw[1 - devpriv->dma_actbuf] >> 9) & 0xff,
- dev->iobase + PCI9118_CNT0);
- devpriv->AdFunctionReg |= AdFunction_Start;
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
+ struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[next_buf];
+
+ devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG |
+ PCI9118_AI_CFG_AM;
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
+ pci9118_timer_set_mode(dev, 0, I8254_MODE0);
+ pci9118_timer_write(dev, 0, dmabuf->hw >> 1);
+ devpriv->ai_cfg |= PCI9118_AI_CFG_START;
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
}
static unsigned int defragment_dma_buffer(struct comedi_device *dev,
@@ -689,9 +473,9 @@ static unsigned int defragment_dma_buffer(struct comedi_device *dev,
}
static int move_block_from_dma(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned short *dma_buffer,
- unsigned int num_samples)
+ struct comedi_subdevice *s,
+ unsigned short *dma_buffer,
+ unsigned int num_samples)
{
struct pci9118_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
@@ -710,100 +494,59 @@ static int move_block_from_dma(struct comedi_device *dev,
return 0;
}
-static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source)
+static void pci9118_exttrg_enable(struct comedi_device *dev, bool enable)
{
struct pci9118_private *devpriv = dev->private;
- if (source > 3)
- return -1; /* incorrect source */
- devpriv->exttrg_users |= (1 << source);
- devpriv->IntControlReg |= Int_DTrg;
- outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
- outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00,
- devpriv->iobase_a + AMCC_OP_REG_INTCSR);
- /* allow INT in AMCC */
- return 0;
-}
-
-static int pci9118_exttrg_del(struct comedi_device *dev, unsigned char source)
-{
- struct pci9118_private *devpriv = dev->private;
+ if (enable)
+ devpriv->int_ctrl |= PCI9118_INT_CTRL_DTRG;
+ else
+ devpriv->int_ctrl &= ~PCI9118_INT_CTRL_DTRG;
+ outl(devpriv->int_ctrl, dev->iobase + PCI9118_INT_CTRL_REG);
- if (source > 3)
- return -1; /* incorrect source */
- devpriv->exttrg_users &= ~(1 << source);
- if (!devpriv->exttrg_users) { /* shutdown ext trg intterrupts */
- devpriv->IntControlReg &= ~Int_DTrg;
- if (!devpriv->IntControlReg) /* all IRQ disabled */
- outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) &
- (~0x00001f00),
- devpriv->iobase_a + AMCC_OP_REG_INTCSR);
- /* disable int in AMCC */
- outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
- }
- return 0;
+ if (devpriv->int_ctrl)
+ pci9118_amcc_int_ena(dev, true);
+ else
+ pci9118_amcc_int_ena(dev, false);
}
-static void pci9118_calc_divisors(char mode, struct comedi_device *dev,
+static void pci9118_calc_divisors(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int *tim1, unsigned int *tim2,
unsigned int flags, int chans,
unsigned int *div1, unsigned int *div2,
unsigned int chnsshfront)
{
- const struct boardtype *this_board = comedi_board(dev);
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(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 / I8254_OSC_BASE_4MHZ;
- /* convert timer (burst) */
- if (*div1 < this_board->ai_pacer_min)
- *div1 = this_board->ai_pacer_min;
- *div2 = *tim1 / I8254_OSC_BASE_4MHZ; /* scan timer */
- *div2 = *div2 / *div1; /* major timer is c1*c2 */
- if (*div2 < chans)
- *div2 = chans;
-
- *tim2 = *div1 * I8254_OSC_BASE_4MHZ; /* real convert timer */
-
- if (cmd->convert_src == TRIG_NOW && !chnsshfront) {
- /* use BSSH signal */
- if (*div2 < (chans + 2))
- *div2 = chans + 2;
- }
+ *div1 = *tim2 / I8254_OSC_BASE_4MHZ; /* convert timer (burst) */
+ *div2 = *tim1 / I8254_OSC_BASE_4MHZ; /* scan timer */
+ *div2 = *div2 / *div1; /* major timer is c1*c2 */
+ if (*div2 < chans)
+ *div2 = chans;
- *tim1 = *div1 * *div2 * I8254_OSC_BASE_4MHZ;
- break;
+ *tim2 = *div1 * I8254_OSC_BASE_4MHZ; /* real convert timer */
+
+ if (cmd->convert_src == TRIG_NOW && !chnsshfront) {
+ /* use BSSH signal */
+ if (*div2 < (chans + 2))
+ *div2 = chans + 2;
}
+
+ *tim1 = *div1 * *div2 * I8254_OSC_BASE_4MHZ;
}
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); */
+ pci9118_timer_set_mode(dev, 1, I8254_MODE2);
+ pci9118_timer_set_mode(dev, 2, I8254_MODE2);
udelay(1);
if ((mode == 1) || (mode == 2) || (mode == 4)) {
- outl(divisor2 & 0xff, dev->iobase + PCI9118_CNT2);
- outl((divisor2 >> 8) & 0xff, dev->iobase + PCI9118_CNT2);
- outl(divisor1 & 0xff, dev->iobase + PCI9118_CNT1);
- outl((divisor1 >> 8) & 0xff, dev->iobase + PCI9118_CNT1);
+ pci9118_timer_write(dev, 2, devpriv->ai_divisor2);
+ pci9118_timer_write(dev, 1, devpriv->ai_divisor1);
}
}
@@ -813,29 +556,24 @@ static int pci9118_ai_cancel(struct comedi_device *dev,
struct pci9118_private *devpriv = dev->private;
if (devpriv->usedma)
- outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) &
- (~EN_A2P_TRANSFERS),
- devpriv->iobase_a + AMCC_OP_REG_MCSR); /* stop DMA */
- pci9118_exttrg_del(dev, EXTTRG_AI);
+ pci9118_amcc_dma_ena(dev, false);
+ pci9118_exttrg_enable(dev, false);
pci9118_start_pacer(dev, 0); /* stop 8254 counters */
- devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg;
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
- /*
- * positive triggers, no S&H, no burst,
- * burst stop, no post trigger,
- * no about trigger, trigger stop
- */
- devpriv->AdControlReg = 0x00;
- outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
- /*
- * bipolar, S.E., use 8254, stop 8354,
- * internal trigger, soft trigger,
- * disable INT and DMA
- */
- outl(0, dev->iobase + PCI9118_BURST);
- outl(1, dev->iobase + PCI9118_SCANMOD);
- outl(2, dev->iobase + PCI9118_SCANMOD); /* reset scan queue */
- outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
+ /* set default config (disable burst and triggers) */
+ devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG;
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
+ /* reset acqusition control */
+ devpriv->ai_ctrl = 0;
+ outl(devpriv->ai_ctrl, dev->iobase + PCI9118_AI_CTRL_REG);
+ outl(0, dev->iobase + PCI9118_AI_BURST_NUM_REG);
+ /* reset scan queue */
+ outl(1, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+ outl(2, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+ pci9118_ai_reset_fifo(dev);
+
+ devpriv->int_ctrl = 0;
+ outl(devpriv->int_ctrl, dev->iobase + PCI9118_INT_CTRL_REG);
+ pci9118_amcc_int_ena(dev, false);
devpriv->ai_do = 0;
devpriv->usedma = 0;
@@ -847,44 +585,6 @@ static int pci9118_ai_cancel(struct comedi_device *dev,
devpriv->ai_neverending = 0;
devpriv->dma_actbuf = 0;
- if (!devpriv->IntControlReg)
- outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00,
- devpriv->iobase_a + AMCC_OP_REG_INTCSR);
- /* allow INT in AMCC */
-
- return 0;
-}
-
-static char pci9118_decode_error_status(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned char m)
-{
- struct pci9118_private *devpriv = dev->private;
-
- if (m & 0x100) {
- dev_err(dev->class_dev,
- "A/D FIFO Full status (Fatal Error!)\n");
- devpriv->ai_maskerr &= ~0x100L;
- }
- if (m & 0x008) {
- dev_err(dev->class_dev,
- "A/D Burst Mode Overrun Status (Fatal Error!)\n");
- devpriv->ai_maskerr &= ~0x008L;
- }
- if (m & 0x004) {
- dev_err(dev->class_dev, "A/D Over Speed Status (Warning!)\n");
- devpriv->ai_maskerr &= ~0x004L;
- }
- if (m & 0x002) {
- dev_err(dev->class_dev, "A/D Overrun Status (Fatal Error!)\n");
- devpriv->ai_maskerr &= ~0x002L;
- }
- if (m & devpriv->ai_maskharderr) {
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- cfc_handle_events(dev, s);
- return 1;
- }
-
return 0;
}
@@ -909,35 +609,14 @@ static void pci9118_ai_munge(struct comedi_device *dev,
}
static void interrupt_pci9118_ai_onesample(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned short int_adstat,
- unsigned int int_amcc,
- unsigned short int_daq)
+ struct comedi_subdevice *s)
{
struct pci9118_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned short sampl;
- if (int_adstat & devpriv->ai_maskerr)
- if (pci9118_decode_error_status(dev, s, int_adstat))
- return;
-
- sampl = inw(dev->iobase + PCI9118_AD_DATA);
+ sampl = inl(dev->iobase + PCI9118_AI_FIFO_REG);
-#ifdef PCI9118_PARANOIDCHECK
- if (s->maxdata != 0xffff) {
- if ((sampl & 0x000f) != devpriv->chanlist[s->async->cur_chan]) {
- /* data dropout! */
- dev_info(dev->class_dev,
- "A/D SAMPL - data dropout: received channel %d, expected %d!\n",
- sampl & 0x000f,
- devpriv->chanlist[s->async->cur_chan]);
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- cfc_handle_events(dev, s);
- return;
- }
- }
-#endif
cfc_write_to_buffer(s, sampl);
s->async->cur_chan++;
if (s->async->cur_chan >= cmd->scan_end_arg) {
@@ -950,63 +629,33 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev,
s->async->events |= COMEDI_CB_EOA;
}
}
-
- cfc_handle_events(dev, s);
}
static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned short int_adstat,
- unsigned int int_amcc,
- unsigned short int_daq)
+ struct comedi_subdevice *s)
{
struct pci9118_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
+ struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[devpriv->dma_actbuf];
unsigned int next_dma_buf, samplesinbuf, sampls, m;
- if (int_amcc & MASTER_ABORT_INT) {
- dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- cfc_handle_events(dev, s);
- return;
- }
-
- if (int_amcc & TARGET_ABORT_INT) {
- dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- cfc_handle_events(dev, s);
- return;
- }
- if (int_adstat & devpriv->ai_maskerr)
- /* if (int_adstat & 0x106) */
- if (pci9118_decode_error_status(dev, s, int_adstat))
- return;
-
- samplesinbuf = devpriv->dmabuf_use_size[devpriv->dma_actbuf] >> 1;
- /* number of received real samples */
+ samplesinbuf = dmabuf->use_size >> 1; /* number of received samples */
if (devpriv->dma_doublebuf) { /*
* switch DMA buffers if is used
* double buffering
*/
next_dma_buf = 1 - devpriv->dma_actbuf;
- outl(devpriv->dmabuf_hw[next_dma_buf],
- devpriv->iobase_a + AMCC_OP_REG_MWAR);
- outl(devpriv->dmabuf_use_size[next_dma_buf],
- devpriv->iobase_a + AMCC_OP_REG_MWTC);
- devpriv->dmabuf_used_size[next_dma_buf] =
- devpriv->dmabuf_use_size[next_dma_buf];
+ pci9118_amcc_setup_dma(dev, next_dma_buf);
if (devpriv->ai_do == 4)
- interrupt_pci9118_ai_mode4_switch(dev);
+ interrupt_pci9118_ai_mode4_switch(dev, next_dma_buf);
}
if (samplesinbuf) {
/* 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);
+ move_block_from_dma(dev, s, dmabuf->virt, samplesinbuf);
m = m - sampls; /* m=how many samples was transferred */
}
@@ -1016,18 +665,15 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
s->async->events |= COMEDI_CB_EOA;
}
- if (devpriv->dma_doublebuf) { /* switch dma buffers */
+ if (devpriv->dma_doublebuf) {
+ /* switch dma buffers */
devpriv->dma_actbuf = 1 - devpriv->dma_actbuf;
- } else { /* restart DMA if is not used double buffering */
- outl(devpriv->dmabuf_hw[0],
- devpriv->iobase_a + AMCC_OP_REG_MWAR);
- outl(devpriv->dmabuf_use_size[0],
- devpriv->iobase_a + AMCC_OP_REG_MWTC);
+ } else {
+ /* restart DMA if is not used double buffering */
+ pci9118_amcc_setup_dma(dev, 0);
if (devpriv->ai_do == 4)
- interrupt_pci9118_ai_mode4_switch(dev);
+ interrupt_pci9118_ai_mode4_switch(dev, 0);
}
-
- cfc_handle_events(dev, s);
}
static irqreturn_t pci9118_interrupt(int irq, void *d)
@@ -1042,7 +688,7 @@ static irqreturn_t pci9118_interrupt(int irq, void *d)
if (!dev->attached)
return IRQ_NONE;
- intsrc = inl(dev->iobase + PCI9118_INTSRC) & 0xf;
+ intsrc = inl(dev->iobase + PCI9118_INT_CTRL_REG) & 0xf;
intcsr = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR);
if (!intsrc && !(intcsr & ANY_S593X_INT))
@@ -1050,28 +696,63 @@ static irqreturn_t pci9118_interrupt(int irq, void *d)
outl(intcsr | 0x00ff0000, devpriv->iobase_a + AMCC_OP_REG_INTCSR);
- adstat = inw(dev->iobase + PCI9118_ADSTAT) & 0x1ff;
+ if (intcsr & MASTER_ABORT_INT) {
+ dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
+ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ goto interrupt_exit;
+ }
+
+ if (intcsr & TARGET_ABORT_INT) {
+ dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
+ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ goto interrupt_exit;
+ }
+
+ adstat = inl(dev->iobase + PCI9118_AI_STATUS_REG);
+ if ((adstat & PCI9118_AI_STATUS_NFULL) == 0) {
+ dev_err(dev->class_dev,
+ "A/D FIFO Full status (Fatal Error!)\n");
+ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
+ goto interrupt_exit;
+ }
+ if (adstat & PCI9118_AI_STATUS_BOVER) {
+ dev_err(dev->class_dev,
+ "A/D Burst Mode Overrun Status (Fatal Error!)\n");
+ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
+ goto interrupt_exit;
+ }
+ if (adstat & PCI9118_AI_STATUS_ADOS) {
+ dev_err(dev->class_dev, "A/D Over Speed Status (Warning!)\n");
+ s->async->events |= COMEDI_CB_ERROR;
+ goto interrupt_exit;
+ }
+ if (adstat & PCI9118_AI_STATUS_ADOR) {
+ dev_err(dev->class_dev, "A/D Overrun Status (Fatal Error!)\n");
+ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
+ goto interrupt_exit;
+ }
if (!devpriv->ai_do)
return IRQ_HANDLED;
if (devpriv->ai12_startstop) {
- if ((adstat & AdStatus_DTH) && (intsrc & Int_DTrg)) {
+ if ((adstat & PCI9118_AI_STATUS_DTH) &&
+ (intsrc & PCI9118_INT_CTRL_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);
+ pci9118_exttrg_enable(dev, false);
/* start pacer */
pci9118_start_pacer(dev, devpriv->ai_do);
- outl(devpriv->AdControlReg,
- dev->iobase + PCI9118_ADCNTRL);
+ outl(devpriv->ai_ctrl,
+ dev->iobase + PCI9118_AI_CTRL_REG);
} else if (devpriv->ai12_startstop & STOP_AI_EXT) {
/* deactivate EXT trigger */
devpriv->ai12_startstop &= ~STOP_AI_EXT;
- pci9118_exttrg_del(dev, EXTTRG_AI);
+ pci9118_exttrg_enable(dev, false);
/* on next interrupt measure will stop */
devpriv->ai_neverending = 0;
@@ -1080,198 +761,41 @@ static irqreturn_t pci9118_interrupt(int irq, void *d)
}
if (devpriv->usedma)
- interrupt_pci9118_ai_dma(dev, s, adstat, intcsr, intsrc);
+ interrupt_pci9118_ai_dma(dev, s);
else
- interrupt_pci9118_ai_onesample(dev, s, adstat, intcsr, intsrc);
+ interrupt_pci9118_ai_onesample(dev, s);
+interrupt_exit:
+ cfc_handle_events(dev, s);
return IRQ_HANDLED;
}
-static int pci9118_ai_inttrig(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int trig_num)
+static void pci9118_ai_cmd_start(struct comedi_device *dev)
{
struct pci9118_private *devpriv = dev->private;
- struct comedi_cmd *cmd = &s->async->cmd;
-
- if (trig_num != cmd->start_arg)
- return -EINVAL;
-
- devpriv->ai12_startstop &= ~START_AI_INT;
- s->async->inttrig = NULL;
- outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
+ outl(devpriv->int_ctrl, dev->iobase + PCI9118_INT_CTRL_REG);
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
if (devpriv->ai_do != 3) {
pci9118_start_pacer(dev, devpriv->ai_do);
- devpriv->AdControlReg |= AdControl_SoftG;
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_SOFTG;
}
- outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
-
- return 1;
+ outl(devpriv->ai_ctrl, dev->iobase + PCI9118_AI_CTRL_REG);
}
-static int pci9118_ai_cmdtest(struct comedi_device *dev,
+static int pci9118_ai_inttrig(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
+ unsigned int trig_num)
{
- const struct boardtype *this_board = comedi_board(dev);
- struct pci9118_private *devpriv = dev->private;
- int err = 0;
- unsigned int flags;
- unsigned int arg;
- unsigned int divisor1 = 0, divisor2 = 0;
-
- /* Step 1 : check if triggers are trivially valid */
-
- err |= cfc_check_trigger_src(&cmd->start_src,
- TRIG_NOW | TRIG_EXT | TRIG_INT);
-
- flags = TRIG_FOLLOW;
- if (devpriv->master)
- flags |= TRIG_TIMER | TRIG_EXT;
- err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags);
-
- flags = TRIG_TIMER | TRIG_EXT;
- if (devpriv->master)
- flags |= TRIG_NOW;
- err |= cfc_check_trigger_src(&cmd->convert_src, flags);
-
- err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
- err |= cfc_check_trigger_src(&cmd->stop_src,
- TRIG_COUNT | TRIG_NONE | TRIG_EXT);
-
- if (err)
- return 1;
-
- /* Step 2a : make sure trigger sources are unique */
-
- err |= cfc_check_trigger_is_unique(cmd->start_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->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT)
- err |= -EINVAL;
-
- if (cmd->start_src == TRIG_INT && cmd->scan_begin_src == TRIG_INT)
- err |= -EINVAL;
-
- if ((cmd->scan_begin_src & (TRIG_TIMER | TRIG_EXT)) &&
- (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW))))
- err |= -EINVAL;
-
- if ((cmd->scan_begin_src == TRIG_FOLLOW) &&
- (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT))))
- err |= -EINVAL;
-
- if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT)
- err |= -EINVAL;
-
- if (err)
- return 2;
-
- /* Step 3: check if arguments are trivially valid */
-
- 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);
-
- if ((cmd->scan_begin_src == TRIG_TIMER) &&
- (cmd->convert_src == TRIG_TIMER) && (cmd->scan_end_arg == 1)) {
- cmd->scan_begin_src = TRIG_FOLLOW;
- cmd->convert_arg = cmd->scan_begin_arg;
- cmd->scan_begin_arg = 0;
- }
-
- if (cmd->scan_begin_src == TRIG_TIMER)
- err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
- this_board->ai_ns_min);
-
- if (cmd->scan_begin_src == TRIG_EXT)
- if (cmd->scan_begin_arg) {
- cmd->scan_begin_arg = 0;
- err |= -EINVAL;
- err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg,
- 65535);
- }
-
- if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW))
- err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
- this_board->ai_ns_min);
-
- if (cmd->convert_src == TRIG_EXT)
- err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
-
- 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);
-
- err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
-
- err |= cfc_check_trigger_arg_min(&cmd->scan_end_arg,
- cmd->chanlist_len);
-
- if ((cmd->scan_end_arg % cmd->chanlist_len)) {
- cmd->scan_end_arg =
- cmd->chanlist_len * (cmd->scan_end_arg / cmd->chanlist_len);
- err |= -EINVAL;
- }
-
- if (err)
- return 3;
-
- /* step 4: fix up any arguments */
-
- if (cmd->scan_begin_src == TRIG_TIMER) {
- arg = cmd->scan_begin_arg;
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
- &divisor1, &divisor2,
- &arg, cmd->flags);
- err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
- }
-
- if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) {
- arg = cmd->convert_arg;
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
- &divisor1, &divisor2,
- &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) {
- arg = this_board->ai_ns_min *
- (cmd->scan_end_arg + 2);
- } else {
- arg = cmd->convert_arg * cmd->chanlist_len;
- }
- err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
- arg);
- }
- }
+ struct comedi_cmd *cmd = &s->async->cmd;
- if (err)
- return 4;
+ if (trig_num != cmd->start_arg)
+ return -EINVAL;
- if (cmd->chanlist)
- if (!check_channel_list(dev, s, cmd->chanlist_len,
- cmd->chanlist, 0, 0))
- return 5; /* incorrect channels list */
+ s->async->inttrig = NULL;
+ pci9118_ai_cmd_start(dev);
- return 0;
+ return 1;
}
static int Compute_and_setup_dma(struct comedi_device *dev,
@@ -1279,10 +803,12 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
{
struct pci9118_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
+ struct pci9118_dmabuf *dmabuf0 = &devpriv->dmabuf[0];
+ struct pci9118_dmabuf *dmabuf1 = &devpriv->dmabuf[1];
unsigned int dmalen0, dmalen1, i;
- dmalen0 = devpriv->dmabuf_size[0];
- dmalen1 = devpriv->dmabuf_size[1];
+ dmalen0 = dmabuf0->size;
+ dmalen1 = dmabuf1->size;
/* isn't output buff smaller that our DMA buff? */
if (dmalen0 > s->async->prealloc_bufsz) {
/* align to 32bit down */
@@ -1294,12 +820,12 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
}
/* we want wake up every scan? */
- if (devpriv->ai_flags & TRIG_WAKE_EOS) {
+ if (devpriv->ai_flags & CMDF_WAKE_EOS) {
if (dmalen0 < (devpriv->ai_n_realscanlen << 1)) {
/* uff, too short DMA buffer, disable EOS support! */
- devpriv->ai_flags &= (~TRIG_WAKE_EOS);
+ devpriv->ai_flags &= (~CMDF_WAKE_EOS);
dev_info(dev->class_dev,
- "WAR: DMA0 buf too short, can't support TRIG_WAKE_EOS (%d<%d)\n",
+ "WAR: DMA0 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n",
dmalen0, devpriv->ai_n_realscanlen << 1);
} else {
/* short first DMA buffer to one scan */
@@ -1312,12 +838,12 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
}
}
}
- if (devpriv->ai_flags & TRIG_WAKE_EOS) {
+ if (devpriv->ai_flags & CMDF_WAKE_EOS) {
if (dmalen1 < (devpriv->ai_n_realscanlen << 1)) {
/* uff, too short DMA buffer, disable EOS support! */
- devpriv->ai_flags &= (~TRIG_WAKE_EOS);
+ devpriv->ai_flags &= (~CMDF_WAKE_EOS);
dev_info(dev->class_dev,
- "WAR: DMA1 buf too short, can't support TRIG_WAKE_EOS (%d<%d)\n",
+ "WAR: DMA1 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n",
dmalen1, devpriv->ai_n_realscanlen << 1);
} else {
/* short second DMA buffer to one scan */
@@ -1331,8 +857,8 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
}
}
- /* transfer without TRIG_WAKE_EOS */
- if (!(devpriv->ai_flags & TRIG_WAKE_EOS)) {
+ /* transfer without CMDF_WAKE_EOS */
+ if (!(devpriv->ai_flags & CMDF_WAKE_EOS)) {
/* if it's possible then align DMA buffers to length of scan */
i = dmalen0;
dmalen0 =
@@ -1378,37 +904,16 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
/* these DMA buffer size will be used */
devpriv->dma_actbuf = 0;
- devpriv->dmabuf_use_size[0] = dmalen0;
- devpriv->dmabuf_use_size[1] = dmalen1;
-
-#if 0
- if (cmd->scan_end_arg < this_board->half_fifo_size) {
- devpriv->dmabuf_panic_size[0] =
- (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 / cmd->scan_end_arg +
- 1) * cmd->scan_end_arg * sizeof(short);
- } else {
- devpriv->dmabuf_panic_size[0] =
- (cmd->scan_end_arg << 1) % devpriv->dmabuf_size[0];
- devpriv->dmabuf_panic_size[1] =
- (cmd->scan_end_arg << 1) % devpriv->dmabuf_size[1];
- }
-#endif
+ dmabuf0->use_size = dmalen0;
+ dmabuf1->use_size = dmalen1;
- outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) & (~EN_A2P_TRANSFERS),
- devpriv->iobase_a + AMCC_OP_REG_MCSR); /* stop DMA */
- outl(devpriv->dmabuf_hw[0], devpriv->iobase_a + AMCC_OP_REG_MWAR);
- outl(devpriv->dmabuf_use_size[0], devpriv->iobase_a + AMCC_OP_REG_MWTC);
+ pci9118_amcc_dma_ena(dev, false);
+ pci9118_amcc_setup_dma(dev, 0);
/* init DMA transfer */
outl(0x00000000 | AINT_WRITE_COMPL,
devpriv->iobase_a + AMCC_OP_REG_INTCSR);
/* outl(0x02000000|AINT_WRITE_COMPL, devpriv->iobase_a+AMCC_OP_REG_INTCSR); */
-
- outl(inl(devpriv->iobase_a +
- AMCC_OP_REG_MCSR) | RESET_A2P_FLAGS | A2P_HI_PRIORITY |
- EN_A2P_TRANSFERS, devpriv->iobase_a + AMCC_OP_REG_MCSR);
+ pci9118_amcc_dma_ena(dev, true);
outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | EN_A2P_TRANSFERS,
devpriv->iobase_a + AMCC_OP_REG_INTCSR);
/* allow bus mastering */
@@ -1416,135 +921,16 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
return 0;
}
-static int pci9118_ai_docmd_sampl(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pci9118_private *devpriv = dev->private;
-
- switch (devpriv->ai_do) {
- case 1:
- devpriv->AdControlReg |= AdControl_TmrTr;
- break;
- case 2:
- dev_err(dev->class_dev, "%s mode 2 bug!\n", __func__);
- return -EIO;
- case 3:
- devpriv->AdControlReg |= AdControl_ExtM;
- break;
- case 4:
- dev_err(dev->class_dev, "%s mode 4 bug!\n", __func__);
- return -EIO;
- default:
- dev_err(dev->class_dev, "%s mode number bug!\n", __func__);
- return -EIO;
- }
-
- if (devpriv->ai12_startstop)
- pci9118_exttrg_add(dev, EXTTRG_AI);
- /* activate EXT trigger */
-
- if ((devpriv->ai_do == 1) || (devpriv->ai_do == 2))
- devpriv->IntControlReg |= Int_Timer;
-
- devpriv->AdControlReg |= AdControl_Int;
-
- outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00,
- devpriv->iobase_a + AMCC_OP_REG_INTCSR);
- /* allow INT in AMCC */
-
- if (!(devpriv->ai12_startstop & (START_AI_EXT | START_AI_INT))) {
- outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
- if (devpriv->ai_do != 3) {
- pci9118_start_pacer(dev, devpriv->ai_do);
- devpriv->AdControlReg |= AdControl_SoftG;
- }
- outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
- }
-
- return 0;
-}
-
-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, s);
-
- switch (devpriv->ai_do) {
- case 1:
- devpriv->AdControlReg |=
- ((AdControl_TmrTr | AdControl_Dma) & 0xff);
- break;
- case 2:
- devpriv->AdControlReg |=
- ((AdControl_TmrTr | AdControl_Dma) & 0xff);
- devpriv->AdFunctionReg =
- AdFunction_PDTrg | AdFunction_PETrg | AdFunction_BM |
- AdFunction_BS;
- if (cmd->convert_src == TRIG_NOW && !devpriv->softsshdelay)
- devpriv->AdFunctionReg |= AdFunction_BSSH;
- outl(devpriv->ai_n_realscanlen, dev->iobase + PCI9118_BURST);
- break;
- case 3:
- devpriv->AdControlReg |=
- ((AdControl_ExtM | AdControl_Dma) & 0xff);
- devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg;
- break;
- case 4:
- devpriv->AdControlReg |=
- ((AdControl_TmrTr | AdControl_Dma) & 0xff);
- devpriv->AdFunctionReg =
- AdFunction_PDTrg | AdFunction_PETrg | AdFunction_AM;
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
- outl(0x30, dev->iobase + PCI9118_CNTCTRL);
- outl((devpriv->dmabuf_hw[0] >> 1) & 0xff,
- dev->iobase + PCI9118_CNT0);
- outl((devpriv->dmabuf_hw[0] >> 9) & 0xff,
- dev->iobase + PCI9118_CNT0);
- devpriv->AdFunctionReg |= AdFunction_Start;
- break;
- default:
- dev_err(dev->class_dev, "%s mode number bug!\n", __func__);
- return -EIO;
- }
-
- if (devpriv->ai12_startstop) {
- pci9118_exttrg_add(dev, EXTTRG_AI);
- /* activate EXT trigger */
- }
-
- outl(0x02000000 | AINT_WRITE_COMPL,
- devpriv->iobase_a + AMCC_OP_REG_INTCSR);
-
- if (!(devpriv->ai12_startstop & (START_AI_EXT | START_AI_INT))) {
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
- outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
- if (devpriv->ai_do != 3) {
- pci9118_start_pacer(dev, devpriv->ai_do);
- devpriv->AdControlReg |= AdControl_SoftG;
- }
- outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
- }
-
- return 0;
-}
-
static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
- const struct boardtype *this_board = comedi_board(dev);
struct pci9118_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned int addchans = 0;
- int ret = 0;
devpriv->ai12_startstop = 0;
devpriv->ai_flags = cmd->flags;
devpriv->ai_add_front = 0;
devpriv->ai_add_back = 0;
- devpriv->ai_maskerr = 0x10e;
/* prepare for start/stop conditions */
if (cmd->start_src == TRIG_EXT)
@@ -1553,10 +939,6 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_neverending = 1;
devpriv->ai12_startstop |= STOP_AI_EXT;
}
- if (cmd->start_src == TRIG_INT) {
- devpriv->ai12_startstop |= START_AI_INT;
- s->async->inttrig = pci9118_ai_inttrig;
- }
if (cmd->stop_src == TRIG_NONE)
devpriv->ai_neverending = 1;
if (cmd->stop_src == TRIG_COUNT)
@@ -1570,7 +952,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_add_back = 0;
if (devpriv->master) {
devpriv->usedma = 1;
- if ((cmd->flags & TRIG_WAKE_EOS) &&
+ if ((cmd->flags & CMDF_WAKE_EOS) &&
(cmd->scan_end_arg == 1)) {
if (cmd->convert_src == TRIG_NOW)
devpriv->ai_add_back = 1;
@@ -1582,7 +964,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
*/
}
}
- if ((cmd->flags & TRIG_WAKE_EOS) &&
+ if ((cmd->flags & CMDF_WAKE_EOS) &&
(cmd->scan_end_arg & 1) &&
(cmd->scan_end_arg > 1)) {
if (cmd->scan_begin_src == TRIG_FOLLOW) {
@@ -1612,8 +994,8 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_add_front++;
devpriv->ai_add_back = 0;
}
- if (cmd->convert_arg < this_board->ai_ns_min)
- cmd->convert_arg = this_board->ai_ns_min;
+ if (cmd->convert_arg < devpriv->ai_ns_min)
+ cmd->convert_arg = devpriv->ai_ns_min;
addchans = devpriv->softsshdelay / cmd->convert_arg;
if (devpriv->softsshdelay % cmd->convert_arg)
addchans++;
@@ -1642,171 +1024,432 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
cmd->chanlist, devpriv->ai_add_front,
devpriv->ai_add_back))
return -EINVAL;
- 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 */
/*
- * simplest way, fr=4Mhz/(tim1*tim2),
- * channel manipulation without timers effect
+ * Configure analog input and load the chanlist.
+ * The acqusition control bits are enabled later.
*/
- if (((cmd->scan_begin_src == TRIG_FOLLOW) ||
- (cmd->scan_begin_src == TRIG_EXT) ||
- (cmd->scan_begin_src == TRIG_INT)) &&
- (cmd->convert_src == TRIG_TIMER)) {
- /* both timer is used for one time */
+ pci9118_set_chanlist(dev, s, cmd->chanlist_len, cmd->chanlist,
+ devpriv->ai_add_front, devpriv->ai_add_back);
+
+ /* Determine acqusition mode and calculate timing */
+ devpriv->ai_do = 0;
+ if (cmd->scan_begin_src != TRIG_TIMER &&
+ cmd->convert_src == TRIG_TIMER) {
+ /* cascaded timers 1 and 2 are used for convert timing */
if (cmd->scan_begin_src == TRIG_EXT)
devpriv->ai_do = 4;
else
devpriv->ai_do = 1;
- pci9118_calc_divisors(devpriv->ai_do, dev, s,
- &cmd->scan_begin_arg, &cmd->convert_arg,
- devpriv->ai_flags,
- devpriv->ai_n_realscanlen,
- &devpriv->ai_divisor1,
- &devpriv->ai_divisor2,
- devpriv->ai_add_front);
+
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
+ &devpriv->ai_divisor1,
+ &devpriv->ai_divisor2,
+ &cmd->convert_arg,
+ devpriv->ai_flags &
+ CMDF_ROUND_NEAREST);
+
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_TMRTR;
+
+ if (!devpriv->usedma) {
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_INT;
+ devpriv->int_ctrl |= PCI9118_INT_CTRL_TIMER;
+ }
+
+ if (cmd->scan_begin_src == TRIG_EXT) {
+ struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[0];
+
+ devpriv->ai_cfg |= PCI9118_AI_CFG_AM;
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
+ pci9118_timer_set_mode(dev, 0, I8254_MODE0);
+ pci9118_timer_write(dev, 0, dmabuf->hw >> 1);
+ devpriv->ai_cfg |= PCI9118_AI_CFG_START;
+ }
}
- if ((cmd->scan_begin_src == TRIG_TIMER) &&
- ((cmd->convert_src == TRIG_TIMER) ||
- (cmd->convert_src == TRIG_NOW))) {
- /* double timed action */
+ if (cmd->scan_begin_src == TRIG_TIMER &&
+ cmd->convert_src != TRIG_EXT) {
if (!devpriv->usedma) {
dev_err(dev->class_dev,
"cmd->scan_begin_src=TRIG_TIMER works only with bus mastering!\n");
return -EIO;
}
+ /* double timed action */
devpriv->ai_do = 2;
- pci9118_calc_divisors(devpriv->ai_do, dev, s,
+
+ pci9118_calc_divisors(dev, s,
&cmd->scan_begin_arg, &cmd->convert_arg,
devpriv->ai_flags,
devpriv->ai_n_realscanlen,
&devpriv->ai_divisor1,
&devpriv->ai_divisor2,
devpriv->ai_add_front);
+
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_TMRTR;
+ devpriv->ai_cfg |= PCI9118_AI_CFG_BM | PCI9118_AI_CFG_BS;
+ if (cmd->convert_src == TRIG_NOW && !devpriv->softsshdelay)
+ devpriv->ai_cfg |= PCI9118_AI_CFG_BSSH;
+ outl(devpriv->ai_n_realscanlen,
+ dev->iobase + PCI9118_AI_BURST_NUM_REG);
}
- if ((cmd->scan_begin_src == TRIG_FOLLOW)
- && (cmd->convert_src == TRIG_EXT)) {
+ if (cmd->scan_begin_src == TRIG_FOLLOW &&
+ cmd->convert_src == TRIG_EXT) {
+ /* external trigger conversion */
devpriv->ai_do = 3;
+
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_EXTM;
+ }
+
+ if (devpriv->ai_do == 0) {
+ dev_err(dev->class_dev,
+ "Unable to determine acqusition mode! BUG in (*do_cmdtest)?\n");
+ return -EINVAL;
}
+ if (devpriv->usedma)
+ devpriv->ai_ctrl |= PCI9118_AI_CTRL_DMA;
+
pci9118_start_pacer(dev, -1); /* stop pacer */
- devpriv->AdControlReg = 0; /*
- * bipolar, S.E., use 8254, stop 8354,
- * internal trigger, soft trigger,
- * disable DMA
- */
- outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
- devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg;
- /*
- * positive triggers, no S&H, no burst,
- * burst stop, no post trigger,
- * no about trigger, trigger stop
- */
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
+ /* set default config (disable burst and triggers) */
+ devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG;
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
udelay(1);
- outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
- inl(dev->iobase + PCI9118_ADSTAT); /*
- * flush A/D and INT
- * status register
- */
- inl(dev->iobase + PCI9118_INTSRC);
+ pci9118_ai_reset_fifo(dev);
+
+ /* clear A/D and INT status registers */
+ inl(dev->iobase + PCI9118_AI_STATUS_REG);
+ inl(dev->iobase + PCI9118_INT_CTRL_REG);
devpriv->ai_act_scan = 0;
devpriv->ai_act_dmapos = 0;
s->async->cur_chan = 0;
- if (devpriv->usedma)
- ret = pci9118_ai_docmd_dma(dev, s);
- else
- ret = pci9118_ai_docmd_sampl(dev, s);
+ if (devpriv->usedma) {
+ Compute_and_setup_dma(dev, s);
+
+ outl(0x02000000 | AINT_WRITE_COMPL,
+ devpriv->iobase_a + AMCC_OP_REG_INTCSR);
+ } else {
+ pci9118_amcc_int_ena(dev, true);
+ }
- return ret;
+ /* start async command now or wait for internal trigger */
+ if (cmd->start_src == TRIG_NOW)
+ pci9118_ai_cmd_start(dev);
+ else if (cmd->start_src == TRIG_INT)
+ s->async->inttrig = pci9118_ai_inttrig;
+
+ /* enable external trigger for command start/stop */
+ if (cmd->start_src == TRIG_EXT || cmd->stop_src == TRIG_EXT)
+ pci9118_exttrg_enable(dev, true);
+
+ return 0;
}
-static int pci9118_reset(struct comedi_device *dev)
+static int pci9118_ai_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
{
struct pci9118_private *devpriv = dev->private;
+ int err = 0;
+ unsigned int flags;
+ unsigned int arg;
+ unsigned int divisor1 = 0, divisor2 = 0;
- devpriv->IntControlReg = 0;
- devpriv->exttrg_users = 0;
- inl(dev->iobase + PCI9118_INTCTRL);
- outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL);
- /* disable interrupts source */
- outl(0x30, dev->iobase + PCI9118_CNTCTRL);
-/* outl(0xb4, dev->iobase + PCI9118_CNTCTRL); */
- pci9118_start_pacer(dev, 0); /* stop 8254 counters */
- devpriv->AdControlReg = 0;
- outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
- /*
- * bipolar, S.E., use 8254,
- * stop 8354, internal trigger,
- * soft trigger,
- * disable INT and DMA
- */
- outl(0, dev->iobase + PCI9118_BURST);
- outl(1, dev->iobase + PCI9118_SCANMOD);
- outl(2, dev->iobase + PCI9118_SCANMOD); /* reset scan queue */
- devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg;
- outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC);
- /*
- * positive triggers, no S&H,
- * no burst, burst stop,
- * no post trigger,
- * no about trigger,
- * trigger stop
- */
+ /* Step 1 : check if triggers are trivially valid */
- devpriv->ao_data[0] = 2047;
- devpriv->ao_data[1] = 2047;
- outl(devpriv->ao_data[0], dev->iobase + PCI9118_DA1);
- /* reset A/D outs to 0V */
- outl(devpriv->ao_data[1], dev->iobase + PCI9118_DA2);
- outl(0, dev->iobase + PCI9118_DO); /* reset digi outs to L */
- udelay(10);
- inl(dev->iobase + PCI9118_AD_DATA);
- outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */
- outl(0, dev->iobase + PCI9118_INTSRC); /* remove INT requests */
- inl(dev->iobase + PCI9118_ADSTAT); /* flush A/D status register */
- inl(dev->iobase + PCI9118_INTSRC); /* flush INT requests */
- devpriv->AdControlReg = 0;
- outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL);
- /*
- * bipolar, S.E., use 8254,
- * stop 8354, internal trigger,
- * soft trigger,
- * disable INT and DMA
- */
+ err |= cfc_check_trigger_src(&cmd->start_src,
+ TRIG_NOW | TRIG_EXT | TRIG_INT);
+
+ flags = TRIG_FOLLOW;
+ if (devpriv->master)
+ flags |= TRIG_TIMER | TRIG_EXT;
+ err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags);
+
+ flags = TRIG_TIMER | TRIG_EXT;
+ if (devpriv->master)
+ flags |= TRIG_NOW;
+ err |= cfc_check_trigger_src(&cmd->convert_src, flags);
+
+ err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+ err |= cfc_check_trigger_src(&cmd->stop_src,
+ TRIG_COUNT | TRIG_NONE | TRIG_EXT);
+
+ if (err)
+ return 1;
+
+ /* Step 2a : make sure trigger sources are unique */
+
+ err |= cfc_check_trigger_is_unique(cmd->start_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->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT)
+ err |= -EINVAL;
+
+ if (cmd->start_src == TRIG_INT && cmd->scan_begin_src == TRIG_INT)
+ err |= -EINVAL;
- devpriv->exttrg_users = 0;
+ if ((cmd->scan_begin_src & (TRIG_TIMER | TRIG_EXT)) &&
+ (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW))))
+ err |= -EINVAL;
+
+ if ((cmd->scan_begin_src == TRIG_FOLLOW) &&
+ (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT))))
+ err |= -EINVAL;
+
+ if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT)
+ err |= -EINVAL;
+
+ if (err)
+ return 2;
+
+ /* Step 3: check if arguments are trivially valid */
+
+ 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);
+
+ if ((cmd->scan_begin_src == TRIG_TIMER) &&
+ (cmd->convert_src == TRIG_TIMER) && (cmd->scan_end_arg == 1)) {
+ cmd->scan_begin_src = TRIG_FOLLOW;
+ cmd->convert_arg = cmd->scan_begin_arg;
+ cmd->scan_begin_arg = 0;
+ }
+
+ if (cmd->scan_begin_src == TRIG_TIMER)
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ devpriv->ai_ns_min);
+
+ if (cmd->scan_begin_src == TRIG_EXT)
+ if (cmd->scan_begin_arg) {
+ cmd->scan_begin_arg = 0;
+ err |= -EINVAL;
+ err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg,
+ 65535);
+ }
+
+ if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW))
+ err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
+ devpriv->ai_ns_min);
+
+ if (cmd->convert_src == TRIG_EXT)
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
+
+ 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);
+
+ err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
+
+ err |= cfc_check_trigger_arg_min(&cmd->scan_end_arg,
+ cmd->chanlist_len);
+
+ if ((cmd->scan_end_arg % cmd->chanlist_len)) {
+ cmd->scan_end_arg =
+ cmd->chanlist_len * (cmd->scan_end_arg / cmd->chanlist_len);
+ err |= -EINVAL;
+ }
+
+ if (err)
+ return 3;
+
+ /* step 4: fix up any arguments */
+
+ if (cmd->scan_begin_src == TRIG_TIMER) {
+ arg = cmd->scan_begin_arg;
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
+ &divisor1, &divisor2,
+ &arg, cmd->flags);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
+ }
+
+ if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) {
+ arg = cmd->convert_arg;
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
+ &divisor1, &divisor2,
+ &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) {
+ arg = devpriv->ai_ns_min *
+ (cmd->scan_end_arg + 2);
+ } else {
+ arg = cmd->convert_arg * cmd->chanlist_len;
+ }
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ arg);
+ }
+ }
+
+ if (err)
+ return 4;
+
+ if (cmd->chanlist)
+ if (!check_channel_list(dev, s, cmd->chanlist_len,
+ cmd->chanlist, 0, 0))
+ return 5; /* incorrect channels list */
return 0;
}
-/*
- * FIXME - this is pretty ineffective because all the supported board types
- * have the same device ID!
- */
-static const struct boardtype *pci9118_find_boardinfo(struct pci_dev *pcidev)
+static int pci9118_ai_eoc(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned long context)
{
- unsigned int i;
+ unsigned int status;
- for (i = 0; i < ARRAY_SIZE(boardtypes); i++)
- if (pcidev->device == boardtypes[i].device_id)
- return &boardtypes[i];
- return NULL;
+ status = inl(dev->iobase + PCI9118_AI_STATUS_REG);
+ if (status & PCI9118_AI_STATUS_ADRDY)
+ return 0;
+ return -EBUSY;
+}
+
+static void pci9118_ai_start_conv(struct comedi_device *dev)
+{
+ /* writing any value triggers an A/D conversion */
+ outl(0, dev->iobase + PCI9118_SOFTTRG_REG);
+}
+
+static int pci9118_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct pci9118_private *devpriv = dev->private;
+ unsigned int val;
+ int ret;
+ int i;
+
+ /*
+ * Configure analog input based on the chanspec.
+ * Acqusition is software controlled without interrupts.
+ */
+ pci9118_set_chanlist(dev, s, 1, &insn->chanspec, 0, 0);
+
+ /* set default config (disable burst and triggers) */
+ devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG;
+ outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
+
+ pci9118_ai_reset_fifo(dev);
+
+ for (i = 0; i < insn->n; i++) {
+ pci9118_ai_start_conv(dev);
+
+ ret = comedi_timeout(dev, s, insn, pci9118_ai_eoc, 0);
+ if (ret)
+ return ret;
+
+ val = inl(dev->iobase + PCI9118_AI_FIFO_REG);
+ if (s->maxdata == 0xffff)
+ data[i] = (val & 0xffff) ^ 0x8000;
+ else
+ data[i] = (val >> 4) & 0xfff;
+ }
+
+ return insn->n;
+}
+
+static int pci9118_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = s->readback[chan];
+ int i;
+
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+ outl(val, dev->iobase + PCI9118_AO_REG(chan));
+ }
+ s->readback[chan] = val;
+
+ return insn->n;
+}
+
+static int pci9118_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ /*
+ * The digital inputs and outputs share the read register.
+ * bits [7:4] are the digital outputs
+ * bits [3:0] are the digital inputs
+ */
+ data[1] = inl(dev->iobase + PCI9118_DIO_REG) & 0xf;
+
+ return insn->n;
+}
+
+static int pci9118_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ /*
+ * The digital outputs are set with the same register that
+ * the digital inputs and outputs are read from. But the
+ * outputs are set with bits [3:0] so we can simply write
+ * the s->state to set them.
+ */
+ if (comedi_dio_update_state(s, data))
+ outl(s->state, dev->iobase + PCI9118_DIO_REG);
+
+ data[1] = s->state;
+
+ return insn->n;
+}
+
+static void pci9118_reset(struct comedi_device *dev)
+{
+ /* reset analog input subsystem */
+ outl(0, dev->iobase + PCI9118_INT_CTRL_REG);
+ outl(0, dev->iobase + PCI9118_AI_CTRL_REG);
+ outl(0, dev->iobase + PCI9118_AI_CFG_REG);
+ pci9118_ai_reset_fifo(dev);
+
+ /* clear any pending interrupts and status */
+ inl(dev->iobase + PCI9118_INT_CTRL_REG);
+ inl(dev->iobase + PCI9118_AI_STATUS_REG);
+
+ /* reset and stop counters */
+ pci9118_timer_set_mode(dev, 0, I8254_MODE0);
+ pci9118_start_pacer(dev, 0);
+
+ /* reset DMA and scan queue */
+ outl(0, dev->iobase + PCI9118_AI_BURST_NUM_REG);
+ outl(1, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+ outl(2, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
+
+ /* reset analog outputs to 0V */
+ outl(2047, dev->iobase + PCI9118_AO_REG(0));
+ outl(2047, dev->iobase + PCI9118_AO_REG(1));
}
static struct pci_dev *pci9118_find_pci(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- const struct boardtype *this_board = comedi_board(dev);
struct pci_dev *pcidev = NULL;
int bus = it->options[0];
int slot = it->options[1];
@@ -1814,7 +1457,7 @@ static struct pci_dev *pci9118_find_pci(struct comedi_device *dev,
for_each_pci_dev(pcidev) {
if (pcidev->vendor != PCI_VENDOR_ID_AMCC)
continue;
- if (pcidev->device != this_board->device_id)
+ if (pcidev->device != 0x80d9)
continue;
if (bus || slot) {
/* requested particular bus/slot */
@@ -1830,56 +1473,85 @@ static struct pci_dev *pci9118_find_pci(struct comedi_device *dev,
return NULL;
}
-static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
- int master, int ext_mux, int softsshdelay,
- int hw_err_mask)
+static void pci9118_alloc_dma(struct comedi_device *dev)
+{
+ struct pci9118_private *devpriv = dev->private;
+ struct pci9118_dmabuf *dmabuf;
+ int order;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ dmabuf = &devpriv->dmabuf[i];
+ for (order = 2; order >= 0; order--) {
+ dmabuf->virt =
+ dma_alloc_coherent(dev->hw_dev, PAGE_SIZE << order,
+ &dmabuf->hw, GFP_KERNEL);
+ if (dmabuf->virt)
+ break;
+ }
+ if (!dmabuf->virt)
+ break;
+ dmabuf->size = PAGE_SIZE << order;
+
+ if (i == 0)
+ devpriv->master = 1;
+ if (i == 1)
+ devpriv->dma_doublebuf = 1;
+ }
+}
+
+static void pci9118_free_dma(struct comedi_device *dev)
{
- const struct boardtype *this_board = comedi_board(dev);
struct pci9118_private *devpriv = dev->private;
+ struct pci9118_dmabuf *dmabuf;
+ int i;
+
+ if (!devpriv)
+ return;
+
+ for (i = 0; i < 2; i++) {
+ dmabuf = &devpriv->dmabuf[i];
+ if (dmabuf->virt) {
+ dma_free_coherent(dev->hw_dev, dmabuf->size,
+ dmabuf->virt, dmabuf->hw);
+ }
+ }
+}
+
+static int pci9118_common_attach(struct comedi_device *dev,
+ int ext_mux, int softsshdelay)
+{
+ const struct pci9118_boardinfo *board = dev->board_ptr;
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct pci9118_private *devpriv;
struct comedi_subdevice *s;
- int ret, pages, i;
+ int ret;
+ int i;
u16 u16w;
- dev->board_name = this_board->name;
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+ if (!devpriv)
+ return -ENOMEM;
+
ret = comedi_pci_enable(dev);
if (ret)
return ret;
- if (master)
- pci_set_master(pcidev);
+ pci_set_master(pcidev);
devpriv->iobase_a = pci_resource_start(pcidev, 0);
dev->iobase = pci_resource_start(pcidev, 2);
pci9118_reset(dev);
- if (master) { /* alloc DMA buffers */
- devpriv->dma_doublebuf = 0;
- for (i = 0; i < 2; i++) {
- for (pages = 4; pages >= 0; pages--) {
- devpriv->dmabuf_virt[i] =
- (unsigned short *)
- __get_free_pages(GFP_KERNEL, pages);
- if (devpriv->dmabuf_virt[i])
- break;
- }
- if (devpriv->dmabuf_virt[i]) {
- devpriv->dmabuf_pages[i] = pages;
- devpriv->dmabuf_size[i] = PAGE_SIZE * pages;
- devpriv->dmabuf_hw[i] =
- virt_to_bus((void *)
- devpriv->dmabuf_virt[i]);
- }
- }
- if (!devpriv->dmabuf_virt[0]) {
- dev_warn(dev->class_dev,
- "Can't allocate DMA buffer, DMA disabled!\n");
- master = 0;
+ if (pcidev->irq) {
+ ret = request_irq(pcidev->irq, pci9118_interrupt, IRQF_SHARED,
+ dev->board_name, dev);
+ if (ret == 0) {
+ dev->irq = pcidev->irq;
+
+ pci9118_alloc_dma(dev);
}
- if (devpriv->dmabuf_virt[1])
- devpriv->dma_doublebuf = 1;
}
- devpriv->master = master;
if (ext_mux > 0) {
if (ext_mux > 256)
@@ -1887,7 +1559,7 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
if (softsshdelay > 0)
if (ext_mux > 128)
ext_mux = 128;
- devpriv->usemux = ext_mux;
+ devpriv->usemux = 1;
} else {
devpriv->usemux = 0;
}
@@ -1907,70 +1579,81 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
pci_write_config_word(pcidev, PCI_COMMAND, u16w | 64);
/* Enable parity check for parity error */
- if (!disable_irq && pcidev->irq) {
- ret = request_irq(pcidev->irq, pci9118_interrupt, IRQF_SHARED,
- dev->board_name, dev);
- if (ret == 0)
- dev->irq = pcidev->irq;
- }
-
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
return ret;
+ /* Analog Input subdevice */
s = &dev->subdevices[0];
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
- if (devpriv->usemux)
- s->n_chan = devpriv->usemux;
- else
- s->n_chan = this_board->n_aichan;
-
- s->maxdata = this_board->ai_maxdata;
- s->range_table = this_board->rangelist_ai;
- s->insn_read = pci9118_insn_read_ai;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
+ s->n_chan = (devpriv->usemux) ? ext_mux : 16;
+ s->maxdata = board->ai_is_16bit ? 0xffff : 0x0fff;
+ s->range_table = board->is_hg ? &pci9118hg_ai_range
+ : &pci9118_ai_range;
+ s->insn_read = pci9118_ai_insn_read;
if (dev->irq) {
dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->len_chanlist = this_board->n_aichanlist;
- s->do_cmdtest = pci9118_ai_cmdtest;
- s->do_cmd = pci9118_ai_cmd;
- s->cancel = pci9118_ai_cancel;
- s->munge = pci9118_ai_munge;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = PCI9118_CHANLEN;
+ s->do_cmdtest = pci9118_ai_cmdtest;
+ s->do_cmd = pci9118_ai_cmd;
+ s->cancel = pci9118_ai_cancel;
+ s->munge = pci9118_ai_munge;
+ }
+
+ if (s->maxdata == 0xffff) {
+ /*
+ * 16-bit samples are from an ADS7805 A/D converter.
+ * Minimum sampling rate is 10us.
+ */
+ devpriv->ai_ns_min = 10000;
+ } else {
+ /*
+ * 12-bit samples are from an ADS7800 A/D converter.
+ * Minimum sampling rate is 3us.
+ */
+ devpriv->ai_ns_min = 3000;
}
+ /* Analog Output subdevice */
s = &dev->subdevices[1];
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = this_board->n_aochan;
- s->maxdata = this_board->ao_maxdata;
- s->len_chanlist = this_board->n_aochan;
- s->range_table = this_board->rangelist_ao;
- s->insn_write = pci9118_insn_write_ao;
- s->insn_read = pci9118_insn_read_ao;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
+ s->n_chan = 2;
+ s->maxdata = 0x0fff;
+ s->range_table = &range_bipolar10;
+ s->insn_write = pci9118_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
- s = &dev->subdevices[2];
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 4;
- s->maxdata = 1;
- s->len_chanlist = 4;
- s->range_table = &range_digital;
- s->insn_bits = pci9118_insn_bits_di;
+ /* the analog outputs were reset to 0V, make the readback match */
+ for (i = 0; i < s->n_chan; i++)
+ s->readback[i] = 2047;
+ /* Digital Input subdevice */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 4;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pci9118_di_insn_bits;
+
+ /* Digital Output subdevice */
s = &dev->subdevices[3];
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = 4;
- s->maxdata = 1;
- s->len_chanlist = 4;
- s->range_table = &range_digital;
- s->insn_bits = pci9118_insn_bits_do;
-
- devpriv->ai_maskharderr = 0x10a;
- /* default measure crash condition */
- if (hw_err_mask) /* disable some requested */
- devpriv->ai_maskharderr &= ~hw_err_mask;
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pci9118_do_insn_bits;
+
+ /* get the current state of the digital outputs */
+ s->state = inl(dev->iobase + PCI9118_DIO_REG) >> 4;
return 0;
}
@@ -1978,74 +1661,50 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
static int pci9118_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- struct pci9118_private *devpriv;
struct pci_dev *pcidev;
- int ext_mux, disable_irq, master, softsshdelay, hw_err_mask;
+ int ext_mux, softsshdelay;
ext_mux = it->options[2];
- master = ((it->options[3] & 1) == 0);
- disable_irq = ((it->options[3] & 2) != 0);
softsshdelay = it->options[4];
- hw_err_mask = it->options[5];
-
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
pcidev = pci9118_find_pci(dev, it);
if (!pcidev)
return -EIO;
comedi_set_hw_dev(dev, &pcidev->dev);
- return pci9118_common_attach(dev, disable_irq, master, ext_mux,
- softsshdelay, hw_err_mask);
+ return pci9118_common_attach(dev, ext_mux, softsshdelay);
}
static int pci9118_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- struct pci9118_private *devpriv;
+ const struct pci9118_boardinfo *board = NULL;
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
+ if (context < ARRAY_SIZE(pci9118_boards))
+ board = &pci9118_boards[context];
+ if (!board)
+ return -ENODEV;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
- dev->board_ptr = pci9118_find_boardinfo(pcidev);
- if (dev->board_ptr == NULL) {
- dev_err(dev->class_dev,
- "adl_pci9118: cannot determine board type for pci %s\n",
- pci_name(pcidev));
- return -EINVAL;
- }
/*
* Need to 'get' the PCI device to match the 'put' in pci9118_detach().
* (The 'put' also matches the implicit 'get' by pci9118_find_pci().)
*/
pci_dev_get(pcidev);
- /* Don't disable irq, use bus master, no external mux,
- * no sample-hold delay, no error mask. */
- return pci9118_common_attach(dev, 0, 1, 0, 0, 0);
+ /* no external mux, no sample-hold delay */
+ return pci9118_common_attach(dev, 0, 0);
}
static void pci9118_detach(struct comedi_device *dev)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- struct pci9118_private *devpriv = dev->private;
- if (devpriv) {
- if (dev->iobase)
- pci9118_reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (devpriv->dmabuf_virt[0])
- free_pages((unsigned long)devpriv->dmabuf_virt[0],
- devpriv->dmabuf_pages[0]);
- if (devpriv->dmabuf_virt[1])
- free_pages((unsigned long)devpriv->dmabuf_virt[1],
- devpriv->dmabuf_pages[1]);
- }
- comedi_pci_disable(dev);
+ if (dev->iobase)
+ pci9118_reset(dev);
+ comedi_pci_detach(dev);
+ pci9118_free_dma(dev);
if (pcidev)
pci_dev_put(pcidev);
}
@@ -2056,9 +1715,9 @@ static struct comedi_driver adl_pci9118_driver = {
.attach = pci9118_attach,
.auto_attach = pci9118_auto_attach,
.detach = pci9118_detach,
- .num_names = ARRAY_SIZE(boardtypes),
- .board_name = &boardtypes[0].name,
- .offset = sizeof(struct boardtype),
+ .num_names = ARRAY_SIZE(pci9118_boards),
+ .board_name = &pci9118_boards[0].name,
+ .offset = sizeof(struct pci9118_boardinfo),
};
static int adl_pci9118_pci_probe(struct pci_dev *dev,
@@ -2068,8 +1727,11 @@ static int adl_pci9118_pci_probe(struct pci_dev *dev,
id->driver_data);
}
+/* FIXME: All the supported board types have the same device ID! */
static const struct pci_device_id adl_pci9118_pci_table[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) },
+ { PCI_VDEVICE(AMCC, 0x80d9), BOARD_PCI9118DG },
+/* { PCI_VDEVICE(AMCC, 0x80d9), BOARD_PCI9118HG }, */
+/* { PCI_VDEVICE(AMCC, 0x80d9), BOARD_PCI9118HR }, */
{ 0 }
};
MODULE_DEVICE_TABLE(pci, adl_pci9118_pci_table);
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index e19ab958791b..5539bd294862 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -327,7 +327,7 @@ static int pci171x_ai_dropout(struct comedi_device *dev,
unsigned int chan,
unsigned int val)
{
- const struct boardtype *board = comedi_board(dev);
+ const struct boardtype *board = dev->board_ptr;
struct pci1710_private *devpriv = dev->private;
if (board->cardtype != TYPE_PCI1713) {
@@ -413,7 +413,7 @@ static void setup_channel_list(struct comedi_device *dev,
unsigned int *chanlist, unsigned int n_chan,
unsigned int seglen)
{
- const struct boardtype *this_board = comedi_board(dev);
+ const struct boardtype *this_board = dev->board_ptr;
struct pci1710_private *devpriv = dev->private;
unsigned int i, range, chanprog;
@@ -715,7 +715,7 @@ static int pci1720_insn_write_ao(struct comedi_device *dev,
static int pci171x_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- const struct boardtype *this_board = comedi_board(dev);
+ const struct boardtype *this_board = dev->board_ptr;
struct pci1710_private *devpriv = dev->private;
switch (this_board->cardtype) {
@@ -828,7 +828,7 @@ static int move_block_from_fifo(struct comedi_device *dev,
static void pci1710_handle_fifo(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- const struct boardtype *this_board = comedi_board(dev);
+ const struct boardtype *this_board = dev->board_ptr;
struct pci1710_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
int m, samplesinbuf;
@@ -907,7 +907,7 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d)
return IRQ_HANDLED;
}
- if (cmd->flags & TRIG_WAKE_EOS)
+ if (cmd->flags & CMDF_WAKE_EOS)
pci1710_handle_every_sample(dev, s);
else
pci1710_handle_fifo(dev, s);
@@ -932,7 +932,7 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
s->async->cur_chan = 0;
devpriv->CntrlReg &= Control_CNT0;
- if ((cmd->flags & TRIG_WAKE_EOS) == 0)
+ if ((cmd->flags & CMDF_WAKE_EOS) == 0)
devpriv->CntrlReg |= Control_ONEFH;
devpriv->divisor1 = devpriv->next_divisor1;
@@ -968,7 +968,7 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct boardtype *this_board = comedi_board(dev);
+ const struct boardtype *this_board = dev->board_ptr;
struct pci1710_private *devpriv = dev->private;
int err = 0;
unsigned int arg;
@@ -1045,7 +1045,7 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
*/
static int pci171x_reset(struct comedi_device *dev)
{
- const struct boardtype *this_board = comedi_board(dev);
+ const struct boardtype *this_board = dev->board_ptr;
struct pci1710_private *devpriv = dev->private;
outw(0x30, dev->iobase + PCI171x_CNTCTRL);
@@ -1102,7 +1102,7 @@ static int pci1720_reset(struct comedi_device *dev)
*/
static int pci1710_reset(struct comedi_device *dev)
{
- const struct boardtype *this_board = comedi_board(dev);
+ const struct boardtype *this_board = dev->board_ptr;
switch (this_board->cardtype) {
case TYPE_PCI1720:
@@ -1250,9 +1250,7 @@ static void pci1710_detach(struct comedi_device *dev)
{
if (dev->iobase)
pci1710_reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver adv_pci1710_driver = {
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index 1881df459dae..1610e2b406f3 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -286,7 +286,7 @@ static void pci1723_detach(struct comedi_device *dev)
{
if (dev->iobase)
pci1723_reset(dev);
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver adv_pci1723_driver = {
diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c
index bc3c34916768..2697758b1ed9 100644
--- a/drivers/staging/comedi/drivers/adv_pci1724.c
+++ b/drivers/staging/comedi/drivers/adv_pci1724.c
@@ -372,7 +372,7 @@ static struct comedi_driver adv_pci1724_driver = {
.driver_name = "adv_pci1724",
.module = THIS_MODULE,
.auto_attach = adv_pci1724_auto_attach,
- .detach = comedi_pci_disable,
+ .detach = comedi_pci_detach,
};
static int adv_pci1724_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index b8c7d9145a54..f2e2d7e163bf 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -66,7 +66,6 @@ enum hw_io_access {
* subdevice) */
#define SIZE_8254 4 /* 8254 IO space length */
-#define SIZE_8255 4 /* 8255 IO space length */
#define PCIDIO_MAINREG 2 /* main I/O region for all Advantech cards? */
@@ -394,7 +393,6 @@ static const struct dio_boardtype boardtypes[] = {
};
struct pci_dio_private {
- char valid; /* card is usable */
char GlobalIrqEnabled; /* 1= any IRQ source is enabled */
/* PCI-1760 specific data */
unsigned char IDICntEnable; /* counter's counting enable status */
@@ -819,7 +817,7 @@ static int pci1760_reset(struct comedi_device *dev)
*/
static int pci_dio_reset(struct comedi_device *dev)
{
- const struct dio_boardtype *this_board = comedi_board(dev);
+ const struct dio_boardtype *this_board = dev->board_ptr;
switch (this_board->cardtype) {
case TYPE_PCI1730:
@@ -977,7 +975,7 @@ static int pci_dio_add_di(struct comedi_device *dev,
struct comedi_subdevice *s,
const struct diosubd_data *d)
{
- const struct dio_boardtype *this_board = comedi_board(dev);
+ const struct dio_boardtype *this_board = dev->board_ptr;
s->type = COMEDI_SUBD_DI;
s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | d->specflags;
@@ -1007,7 +1005,7 @@ static int pci_dio_add_do(struct comedi_device *dev,
struct comedi_subdevice *s,
const struct diosubd_data *d)
{
- const struct dio_boardtype *this_board = comedi_board(dev);
+ const struct dio_boardtype *this_board = dev->board_ptr;
s->type = COMEDI_SUBD_DO;
s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
@@ -1132,9 +1130,8 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
for (j = 0; j < this_board->sdio[i].regs; j++) {
s = &dev->subdevices[subdev];
ret = subdev_8255_init(dev, s, NULL,
- dev->iobase +
this_board->sdio[i].addr +
- SIZE_8255 * j);
+ j * I8255_SIZE);
if (ret)
return ret;
subdev++;
@@ -1157,8 +1154,6 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
if (this_board->cardtype == TYPE_PCI1760)
pci1760_attach(dev);
- devpriv->valid = 1;
-
pci_dio_reset(dev);
return 0;
@@ -1166,13 +1161,9 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
static void pci_dio_detach(struct comedi_device *dev)
{
- struct pci_dio_private *devpriv = dev->private;
-
- if (devpriv) {
- if (devpriv->valid)
- pci_dio_reset(dev);
- }
- comedi_pci_disable(dev);
+ if (dev->iobase)
+ pci_dio_reset(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver adv_pci_dio_driver = {
diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c
index 324746b14931..538277a691b2 100644
--- a/drivers/staging/comedi/drivers/aio_aio12_8.c
+++ b/drivers/staging/comedi/drivers/aio_aio12_8.c
@@ -97,10 +97,6 @@ static const struct aio12_8_boardtype board_types[] = {
},
};
-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,
@@ -149,28 +145,13 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev,
return insn->n;
}
-static int aio_aio12_8_ao_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct aio12_8_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int val = devpriv->ao_readback[chan];
- int i;
-
- for (i = 0; i < insn->n; i++)
- data[i] = val;
- return insn->n;
-}
-
-static int aio_aio12_8_ao_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int aio_aio12_8_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct aio12_8_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned long port = dev->iobase + AIO12_8_DAC_REG(chan);
- unsigned int val = 0;
+ unsigned int val = s->readback[chan];
int i;
/* enable DACs */
@@ -178,10 +159,9 @@ static int aio_aio12_8_ao_write(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
val = data[i];
- outw(val, port);
+ outw(val, dev->iobase + AIO12_8_DAC_REG(chan));
}
-
- devpriv->ao_readback[chan] = val;
+ s->readback[chan] = val;
return insn->n;
}
@@ -198,8 +178,7 @@ static const struct comedi_lrange range_aio_aio12_8 = {
static int aio_aio12_8_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- const struct aio12_8_boardtype *board = comedi_board(dev);
- struct aio12_8_private *devpriv;
+ const struct aio12_8_boardtype *board = dev->board_ptr;
struct comedi_subdevice *s;
int ret;
@@ -207,10 +186,6 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
if (ret)
return ret;
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
return ret;
@@ -236,16 +211,19 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
s->n_chan = 4;
s->maxdata = 0x0fff;
s->range_table = &range_aio_aio12_8;
- s->insn_read = aio_aio12_8_ao_read;
- s->insn_write = aio_aio12_8_ao_write;
+ s->insn_write = aio_aio12_8_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
s = &dev->subdevices[2];
/* 8255 Digital i/o subdevice */
- ret = subdev_8255_init(dev, s, NULL,
- dev->iobase + AIO12_8_8255_BASE_REG);
+ ret = subdev_8255_init(dev, s, NULL, AIO12_8_8255_BASE_REG);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index 17d2e20663cb..4fe118380218 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -202,100 +202,69 @@
*/
static const struct dio200_board dio200_isa_boards[] = {
{
- .name = "pc212e",
- .bustype = isa_bustype,
- .mainsize = DIO200_IO_SIZE,
- .layout = {
- .n_subdevs = 6,
- .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254, sd_8254,
- sd_intr},
- .sdinfo = {0x00, 0x08, 0x0C, 0x10, 0x14, 0x3F},
- .has_int_sce = true,
- .has_clk_gat_sce = true,
+ .name = "pc212e",
+ .n_subdevs = 6,
+ .sdtype = {
+ sd_8255, sd_8254, sd_8254, sd_8254, sd_8254, sd_intr
},
- },
- {
- .name = "pc214e",
- .bustype = isa_bustype,
- .mainsize = DIO200_IO_SIZE,
- .layout = {
- .n_subdevs = 4,
- .sdtype = {sd_8255, sd_8255, sd_8254, sd_intr},
- .sdinfo = {0x00, 0x08, 0x10, 0x01},
+ .sdinfo = { 0x00, 0x08, 0x0c, 0x10, 0x14, 0x3f },
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
+ }, {
+ .name = "pc214e",
+ .n_subdevs = 4,
+ .sdtype = {
+ sd_8255, sd_8255, sd_8254, sd_intr
},
- },
- {
- .name = "pc215e",
- .bustype = isa_bustype,
- .mainsize = DIO200_IO_SIZE,
- .layout = {
- .n_subdevs = 5,
- .sdtype = {sd_8255, sd_8255, sd_8254, sd_8254, sd_intr},
- .sdinfo = {0x00, 0x08, 0x10, 0x14, 0x3F},
- .has_int_sce = true,
- .has_clk_gat_sce = true,
+ .sdinfo = { 0x00, 0x08, 0x10, 0x01 },
+ }, {
+ .name = "pc215e",
+ .n_subdevs = 5,
+ .sdtype = {
+ sd_8255, sd_8255, sd_8254, sd_8254, sd_intr
},
- },
- {
- .name = "pc218e",
- .bustype = isa_bustype,
- .mainsize = DIO200_IO_SIZE,
- .layout = {
- .n_subdevs = 7,
- .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254, sd_8254,
- sd_intr},
- .sdinfo = {0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x3F},
- .has_int_sce = true,
- .has_clk_gat_sce = true,
+ .sdinfo = { 0x00, 0x08, 0x10, 0x14, 0x3f },
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
+ }, {
+ .name = "pc218e",
+ .n_subdevs = 7,
+ .sdtype = {
+ sd_8254, sd_8254, sd_8255, sd_8254, sd_8254, sd_intr
},
- },
- {
- .name = "pc272e",
- .bustype = isa_bustype,
- .mainsize = DIO200_IO_SIZE,
- .layout = {
- .n_subdevs = 4,
- .sdtype = {sd_8255, sd_8255, sd_8255, sd_intr},
- .sdinfo = {0x00, 0x08, 0x10, 0x3F},
- .has_int_sce = true,
+ .sdinfo = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x3f },
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
+ }, {
+ .name = "pc272e",
+ .n_subdevs = 4,
+ .sdtype = {
+ sd_8255, sd_8255, sd_8255, sd_intr
},
+ .sdinfo = { 0x00, 0x08, 0x10, 0x3f },
+ .has_int_sce = true,
},
};
static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct dio200_board *thisboard = comedi_board(dev);
- struct dio200_private *devpriv;
- unsigned int irq;
int ret;
- irq = it->options[1];
-
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
- ret = comedi_request_region(dev, it->options[0], thisboard->mainsize);
+ ret = comedi_request_region(dev, it->options[0], 0x20);
if (ret)
return ret;
- return amplc_dio200_common_attach(dev, irq, 0);
-}
-
-static void dio200_detach(struct comedi_device *dev)
-{
- amplc_dio200_common_detach(dev);
- comedi_legacy_detach(dev);
+ return amplc_dio200_common_attach(dev, it->options[1], 0);
}
static struct comedi_driver amplc_dio200_driver = {
- .driver_name = "amplc_dio200",
- .module = THIS_MODULE,
- .attach = dio200_attach,
- .detach = dio200_detach,
- .board_name = &dio200_isa_boards[0].name,
- .offset = sizeof(struct dio200_board),
- .num_names = ARRAY_SIZE(dio200_isa_boards),
+ .driver_name = "amplc_dio200",
+ .module = THIS_MODULE,
+ .attach = dio200_attach,
+ .detach = comedi_legacy_detach,
+ .board_name = &dio200_isa_boards[0].name,
+ .offset = sizeof(struct dio200_board),
+ .num_names = ARRAY_SIZE(dio200_isa_boards),
};
module_comedi_driver(amplc_dio200_driver);
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.h b/drivers/staging/comedi/drivers/amplc_dio200.h
index e0afe2cee2d6..d6d6a265c461 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.h
+++ b/drivers/staging/comedi/drivers/amplc_dio200.h
@@ -23,10 +23,6 @@
#ifndef AMPLC_DIO200_H_INCLUDED
#define AMPLC_DIO200_H_INCLUDED
-/* 200 series register area sizes */
-#define DIO200_IO_SIZE 0x20
-#define DIO200_PCIE_IO_SIZE 0x4000
-
/*
* Subdevice types.
*/
@@ -35,42 +31,20 @@ enum dio200_sdtype { sd_none, sd_intr, sd_8255, sd_8254, sd_timer };
#define DIO200_MAX_SUBDEVS 8
#define DIO200_MAX_ISNS 6
-/*
- * Board descriptions.
- */
-
-struct dio200_layout {
+struct dio200_board {
+ const char *name;
+ unsigned char mainbar;
unsigned short n_subdevs; /* number of subdevices */
unsigned char sdtype[DIO200_MAX_SUBDEVS]; /* enum dio200_sdtype */
unsigned char sdinfo[DIO200_MAX_SUBDEVS]; /* depends on sdtype */
bool has_int_sce:1; /* has interrupt enable/status reg */
bool has_clk_gat_sce:1; /* has clock/gate selection registers */
- bool has_enhancements:1; /* has enhanced features */
-};
-
-enum dio200_bustype { isa_bustype, pci_bustype };
-
-struct dio200_board {
- const char *name;
- struct dio200_layout layout;
- enum dio200_bustype bustype;
- unsigned char mainbar;
- unsigned char mainshift;
- unsigned int mainsize;
-};
-
-/*
- * Comedi device private data.
- */
-struct dio200_private {
- int intr_sd;
+ bool is_pcie:1; /* has enhanced features */
};
int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq,
unsigned long req_irq_flags);
-void amplc_dio200_common_detach(struct comedi_device *dev);
-
/* Used by initialization of PCIe boards. */
void amplc_dio200_set_enhance(struct comedi_device *dev, unsigned char val);
diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c
index f0d709e0dafc..2c1bfb09601d 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200_common.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c
@@ -27,15 +27,7 @@
#include "amplc_dio200.h"
#include "comedi_fc.h"
#include "8253.h"
-
-/* 8255 control register bits */
-#define CR_C_LO_IO 0x01
-#define CR_B_IO 0x02
-#define CR_B_MODE 0x04
-#define CR_C_HI_IO 0x08
-#define CR_A_IO 0x10
-#define CR_A_MODE(a) ((a)<<5)
-#define CR_CW 0x80
+#include "8255.h" /* only for register defines */
/* 200 series registers */
#define DIO200_IO_SIZE 0x20
@@ -132,42 +124,26 @@ struct dio200_subdev_intr {
bool active:1;
};
-static inline const struct dio200_layout *
-dio200_board_layout(const struct dio200_board *board)
-{
- return &board->layout;
-}
-
-static inline const struct dio200_layout *
-dio200_dev_layout(struct comedi_device *dev)
-{
- return dio200_board_layout(comedi_board(dev));
-}
-
-/*
- * Read 8-bit register.
- */
static unsigned char dio200_read8(struct comedi_device *dev,
unsigned int offset)
{
- const struct dio200_board *thisboard = comedi_board(dev);
+ const struct dio200_board *board = dev->board_ptr;
- offset <<= thisboard->mainshift;
+ if (board->is_pcie)
+ offset <<= 3;
if (dev->mmio)
return readb(dev->mmio + offset);
return inb(dev->iobase + offset);
}
-/*
- * Write 8-bit register.
- */
-static void dio200_write8(struct comedi_device *dev, unsigned int offset,
- unsigned char val)
+static void dio200_write8(struct comedi_device *dev,
+ unsigned int offset, unsigned char val)
{
- const struct dio200_board *thisboard = comedi_board(dev);
+ const struct dio200_board *board = dev->board_ptr;
- offset <<= thisboard->mainshift;
+ if (board->is_pcie)
+ offset <<= 3;
if (dev->mmio)
writeb(val, dev->mmio + offset);
@@ -175,30 +151,26 @@ static void dio200_write8(struct comedi_device *dev, unsigned int offset,
outb(val, dev->iobase + offset);
}
-/*
- * Read 32-bit register.
- */
static unsigned int dio200_read32(struct comedi_device *dev,
unsigned int offset)
{
- const struct dio200_board *thisboard = comedi_board(dev);
+ const struct dio200_board *board = dev->board_ptr;
- offset <<= thisboard->mainshift;
+ if (board->is_pcie)
+ offset <<= 3;
if (dev->mmio)
return readl(dev->mmio + offset);
return inl(dev->iobase + offset);
}
-/*
- * Write 32-bit register.
- */
-static void dio200_write32(struct comedi_device *dev, unsigned int offset,
- unsigned int val)
+static void dio200_write32(struct comedi_device *dev,
+ unsigned int offset, unsigned int val)
{
- const struct dio200_board *thisboard = comedi_board(dev);
+ const struct dio200_board *board = dev->board_ptr;
- offset <<= thisboard->mainshift;
+ if (board->is_pcie)
+ offset <<= 3;
if (dev->mmio)
writel(val, dev->mmio + offset);
@@ -206,18 +178,15 @@ static void dio200_write32(struct comedi_device *dev, unsigned int offset,
outl(val, dev->iobase + offset);
}
-/*
- * 'insn_bits' function for an 'INTERRUPT' subdevice.
- */
-static int
-dio200_subdev_intr_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int dio200_subdev_intr_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
+ const struct dio200_board *board = dev->board_ptr;
struct dio200_subdev_intr *subpriv = s->private;
- if (layout->has_int_sce) {
+ if (board->has_int_sce) {
/* Just read the interrupt status register. */
data[1] = dio200_read8(dev, subpriv->ofs) & subpriv->valid_isns;
} else {
@@ -228,54 +197,38 @@ dio200_subdev_intr_insn_bits(struct comedi_device *dev,
return insn->n;
}
-/*
- * Called to stop acquisition for an 'INTERRUPT' subdevice.
- */
static void dio200_stop_intr(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
+ const struct dio200_board *board = dev->board_ptr;
struct dio200_subdev_intr *subpriv = s->private;
subpriv->active = false;
subpriv->enabled_isns = 0;
- if (layout->has_int_sce)
+ if (board->has_int_sce)
dio200_write8(dev, subpriv->ofs, 0);
}
-/*
- * Called to start acquisition for an 'INTERRUPT' subdevice.
- */
-static int dio200_start_intr(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static void dio200_start_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
- unsigned int n;
- unsigned isn_bits;
- const struct dio200_layout *layout = dio200_dev_layout(dev);
+ const struct dio200_board *board = dev->board_ptr;
struct dio200_subdev_intr *subpriv = s->private;
struct comedi_cmd *cmd = &s->async->cmd;
- int retval = 0;
+ unsigned int n;
+ unsigned isn_bits;
- if (cmd->stop_src == TRIG_COUNT && subpriv->stopcount == 0) {
- /* An empty acquisition! */
- s->async->events |= COMEDI_CB_EOA;
- subpriv->active = false;
- retval = 1;
- } else {
- /* Determine interrupt sources to enable. */
- isn_bits = 0;
- if (cmd->chanlist) {
- for (n = 0; n < cmd->chanlist_len; n++)
- isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
- }
- isn_bits &= subpriv->valid_isns;
- /* Enable interrupt sources. */
- subpriv->enabled_isns = isn_bits;
- if (layout->has_int_sce)
- dio200_write8(dev, subpriv->ofs, isn_bits);
+ /* Determine interrupt sources to enable. */
+ isn_bits = 0;
+ if (cmd->chanlist) {
+ for (n = 0; n < cmd->chanlist_len; n++)
+ isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
}
-
- return retval;
+ isn_bits &= subpriv->valid_isns;
+ /* Enable interrupt sources. */
+ subpriv->enabled_isns = isn_bits;
+ if (board->has_int_sce)
+ dio200_write8(dev, subpriv->ofs, isn_bits);
}
static int dio200_inttrig_start_intr(struct comedi_device *dev,
@@ -285,7 +238,6 @@ static int dio200_inttrig_start_intr(struct comedi_device *dev,
struct dio200_subdev_intr *subpriv = s->private;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned long flags;
- int event = 0;
if (trig_num != cmd->start_arg)
return -EINVAL;
@@ -293,13 +245,10 @@ static int dio200_inttrig_start_intr(struct comedi_device *dev,
spin_lock_irqsave(&subpriv->spinlock, flags);
s->async->inttrig = NULL;
if (subpriv->active)
- event = dio200_start_intr(dev, s);
+ dio200_start_intr(dev, s);
spin_unlock_irqrestore(&subpriv->spinlock, flags);
- if (event)
- comedi_event(dev, s);
-
return 1;
}
@@ -340,14 +289,10 @@ static void dio200_read_scan_intr(struct comedi_device *dev,
}
}
-/*
- * This is called from the interrupt service routine to handle a read
- * scan on an 'INTERRUPT' subdevice.
- */
static int dio200_handle_read_intr(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
+ const struct dio200_board *board = dev->board_ptr;
struct dio200_subdev_intr *subpriv = s->private;
unsigned triggered;
unsigned intstat;
@@ -359,7 +304,7 @@ static int dio200_handle_read_intr(struct comedi_device *dev,
spin_lock_irqsave(&subpriv->spinlock, flags);
oldevents = s->async->events;
- if (layout->has_int_sce) {
+ if (board->has_int_sce) {
/*
* Collect interrupt sources that have triggered and disable
* them temporarily. Loop around until no extra interrupt
@@ -393,7 +338,7 @@ static int dio200_handle_read_intr(struct comedi_device *dev,
* Reenable them NOW to minimize the time they are disabled.
*/
cur_enabled = subpriv->enabled_isns;
- if (layout->has_int_sce)
+ if (board->has_int_sce)
dio200_write8(dev, subpriv->ofs, cur_enabled);
if (subpriv->active) {
@@ -417,9 +362,6 @@ static int dio200_handle_read_intr(struct comedi_device *dev,
return (triggered != 0);
}
-/*
- * 'cancel' function for an 'INTERRUPT' subdevice.
- */
static int dio200_subdev_intr_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -435,12 +377,9 @@ static int dio200_subdev_intr_cancel(struct comedi_device *dev,
return 0;
}
-/*
- * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
- */
-static int
-dio200_subdev_intr_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd)
+static int dio200_subdev_intr_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
{
int err = 0;
@@ -472,16 +411,10 @@ dio200_subdev_intr_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);
- switch (cmd->stop_src) {
- case TRIG_COUNT:
- /* any count allowed */
- break;
- case TRIG_NONE:
+ 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);
- break;
- default:
- break;
- }
if (err)
return 3;
@@ -493,47 +426,34 @@ dio200_subdev_intr_cmdtest(struct comedi_device *dev,
return 0;
}
-/*
- * 'do_cmd' function for an 'INTERRUPT' subdevice.
- */
static int dio200_subdev_intr_cmd(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct comedi_cmd *cmd = &s->async->cmd;
struct dio200_subdev_intr *subpriv = s->private;
unsigned long flags;
- int event = 0;
spin_lock_irqsave(&subpriv->spinlock, flags);
- subpriv->active = true;
- /* Set up end of acquisition. */
- if (cmd->stop_src == TRIG_COUNT)
- subpriv->stopcount = cmd->stop_arg;
- else /* TRIG_NONE */
- subpriv->stopcount = 0;
+ subpriv->active = true;
+ subpriv->stopcount = cmd->stop_arg;
if (cmd->start_src == TRIG_INT)
s->async->inttrig = dio200_inttrig_start_intr;
else /* TRIG_NOW */
- event = dio200_start_intr(dev, s);
+ dio200_start_intr(dev, s);
spin_unlock_irqrestore(&subpriv->spinlock, flags);
- if (event)
- comedi_event(dev, s);
-
return 0;
}
-/*
- * This function initializes an 'INTERRUPT' subdevice.
- */
-static int
-dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int offset, unsigned valid_isns)
+static int dio200_subdev_intr_init(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int offset,
+ unsigned valid_isns)
{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
+ const struct dio200_board *board = dev->board_ptr;
struct dio200_subdev_intr *subpriv;
subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
@@ -544,13 +464,13 @@ dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
subpriv->valid_isns = valid_isns;
spin_lock_init(&subpriv->spinlock);
- if (layout->has_int_sce)
+ if (board->has_int_sce)
/* Disable interrupt sources. */
dio200_write8(dev, subpriv->ofs, 0);
s->type = COMEDI_SUBD_DI;
s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
- if (layout->has_int_sce) {
+ if (board->has_int_sce) {
s->n_chan = DIO200_MAX_ISNS;
s->len_chanlist = DIO200_MAX_ISNS;
} else {
@@ -568,35 +488,23 @@ dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
-/*
- * Interrupt service routine.
- */
static irqreturn_t dio200_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
- struct dio200_private *devpriv = dev->private;
- struct comedi_subdevice *s;
+ struct comedi_subdevice *s = dev->read_subdev;
int handled;
if (!dev->attached)
return IRQ_NONE;
- if (devpriv->intr_sd >= 0) {
- s = &dev->subdevices[devpriv->intr_sd];
- handled = dio200_handle_read_intr(dev, s);
- } else {
- handled = 0;
- }
+ handled = dio200_handle_read_intr(dev, s);
return IRQ_RETVAL(handled);
}
-/*
- * Read an '8254' counter subdevice channel.
- */
-static unsigned int
-dio200_subdev_8254_read_chan(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int chan)
+static unsigned int dio200_subdev_8254_read_chan(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int chan)
{
struct dio200_subdev_8254 *subpriv = s->private;
unsigned int val;
@@ -610,13 +518,10 @@ dio200_subdev_8254_read_chan(struct comedi_device *dev,
return val;
}
-/*
- * Write an '8254' subdevice channel.
- */
-static void
-dio200_subdev_8254_write_chan(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int chan,
- unsigned int count)
+static void dio200_subdev_8254_write_chan(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int chan,
+ unsigned int count)
{
struct dio200_subdev_8254 *subpriv = s->private;
@@ -625,13 +530,10 @@ dio200_subdev_8254_write_chan(struct comedi_device *dev,
dio200_write8(dev, subpriv->ofs + chan, (count >> 8) & 0xff);
}
-/*
- * Set mode of an '8254' subdevice channel.
- */
-static void
-dio200_subdev_8254_set_mode(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int chan,
- unsigned int mode)
+static void dio200_subdev_8254_set_mode(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int chan,
+ unsigned int mode)
{
struct dio200_subdev_8254 *subpriv = s->private;
unsigned int byte;
@@ -642,12 +544,9 @@ dio200_subdev_8254_set_mode(struct comedi_device *dev,
dio200_write8(dev, subpriv->ofs + i8254_control_reg, byte);
}
-/*
- * Read status byte of an '8254' counter subdevice channel.
- */
-static unsigned int
-dio200_subdev_8254_status(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int chan)
+static unsigned int dio200_subdev_8254_status(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int chan)
{
struct dio200_subdev_8254 *subpriv = s->private;
@@ -658,12 +557,10 @@ dio200_subdev_8254_status(struct comedi_device *dev,
return dio200_read8(dev, subpriv->ofs + chan);
}
-/*
- * Handle 'insn_read' for an '8254' counter subdevice.
- */
-static int
-dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int dio200_subdev_8254_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct dio200_subdev_8254 *subpriv = s->private;
int chan = CR_CHAN(insn->chanspec);
@@ -678,12 +575,10 @@ dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
return insn->n;
}
-/*
- * Handle 'insn_write' for an '8254' counter subdevice.
- */
-static int
-dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int dio200_subdev_8254_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct dio200_subdev_8254 *subpriv = s->private;
int chan = CR_CHAN(insn->chanspec);
@@ -698,24 +593,20 @@ dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
return insn->n;
}
-/*
- * Set gate source for an '8254' counter subdevice channel.
- */
-static int
-dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int counter_number,
- unsigned int gate_src)
+static int dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int counter_number,
+ unsigned int gate_src)
{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
+ const struct dio200_board *board = dev->board_ptr;
struct dio200_subdev_8254 *subpriv = s->private;
unsigned char byte;
- if (!layout->has_clk_gat_sce)
+ if (!board->has_clk_gat_sce)
return -1;
if (counter_number > 2)
return -1;
- if (gate_src > (layout->has_enhancements ? 31 : 7))
+ if (gate_src > (board->is_pcie ? 31 : 7))
return -1;
subpriv->gate_src[counter_number] = gate_src;
@@ -725,18 +616,14 @@ dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
return 0;
}
-/*
- * Get gate source for an '8254' counter subdevice channel.
- */
-static int
-dio200_subdev_8254_get_gate_src(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int counter_number)
+static int dio200_subdev_8254_get_gate_src(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int counter_number)
{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
+ const struct dio200_board *board = dev->board_ptr;
struct dio200_subdev_8254 *subpriv = s->private;
- if (!layout->has_clk_gat_sce)
+ if (!board->has_clk_gat_sce)
return -1;
if (counter_number > 2)
return -1;
@@ -744,24 +631,20 @@ dio200_subdev_8254_get_gate_src(struct comedi_device *dev,
return subpriv->gate_src[counter_number];
}
-/*
- * Set clock source for an '8254' counter subdevice channel.
- */
-static int
-dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int counter_number,
- unsigned int clock_src)
+static int dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int counter_number,
+ unsigned int clock_src)
{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
+ const struct dio200_board *board = dev->board_ptr;
struct dio200_subdev_8254 *subpriv = s->private;
unsigned char byte;
- if (!layout->has_clk_gat_sce)
+ if (!board->has_clk_gat_sce)
return -1;
if (counter_number > 2)
return -1;
- if (clock_src > (layout->has_enhancements ? 31 : 7))
+ if (clock_src > (board->is_pcie ? 31 : 7))
return -1;
subpriv->clock_src[counter_number] = clock_src;
@@ -771,20 +654,16 @@ dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
return 0;
}
-/*
- * Get clock source for an '8254' counter subdevice channel.
- */
-static int
-dio200_subdev_8254_get_clock_src(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int counter_number,
- unsigned int *period_ns)
+static int dio200_subdev_8254_get_clock_src(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int counter_number,
+ unsigned int *period_ns)
{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
+ const struct dio200_board *board = dev->board_ptr;
struct dio200_subdev_8254 *subpriv = s->private;
unsigned clock_src;
- if (!layout->has_clk_gat_sce)
+ if (!board->has_clk_gat_sce)
return -1;
if (counter_number > 2)
return -1;
@@ -794,12 +673,10 @@ dio200_subdev_8254_get_clock_src(struct comedi_device *dev,
return clock_src;
}
-/*
- * Handle 'insn_config' for an '8254' counter subdevice.
- */
-static int
-dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int dio200_subdev_8254_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct dio200_subdev_8254 *subpriv = s->private;
int ret = 0;
@@ -851,14 +728,11 @@ dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
return ret < 0 ? ret : insn->n;
}
-/*
- * This function initializes an '8254' counter subdevice.
- */
-static int
-dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int offset)
+static int dio200_subdev_8254_init(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int offset)
{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
+ const struct dio200_board *board = dev->board_ptr;
struct dio200_subdev_8254 *subpriv;
unsigned int chan;
@@ -876,7 +750,7 @@ dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
spin_lock_init(&subpriv->spinlock);
subpriv->ofs = offset;
- if (layout->has_clk_gat_sce) {
+ if (board->has_clk_gat_sce) {
/* Derive CLK_SCE and GAT_SCE register offsets from
* 8254 offset. */
subpriv->clk_sce_ofs = DIO200_XCLK_SCE + (offset >> 3);
@@ -888,7 +762,7 @@ dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
for (chan = 0; chan < 3; chan++) {
dio200_subdev_8254_set_mode(dev, s, chan,
I8254_MODE0 | I8254_BINARY);
- if (layout->has_clk_gat_sce) {
+ if (board->has_clk_gat_sce) {
/* Gate source 0 is VCC (logic 1). */
dio200_subdev_8254_set_gate_src(dev, s, chan, 0);
/* Clock source 0 is the dedicated clock input. */
@@ -899,26 +773,23 @@ dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
-/*
- * This function sets I/O directions for an '8255' DIO subdevice.
- */
static void dio200_subdev_8255_set_dir(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct dio200_subdev_8255 *subpriv = s->private;
int config;
- config = CR_CW;
+ config = I8255_CTRL_CW;
/* 1 in io_bits indicates output, 1 in config indicates input */
if (!(s->io_bits & 0x0000ff))
- config |= CR_A_IO;
+ config |= I8255_CTRL_A_IO;
if (!(s->io_bits & 0x00ff00))
- config |= CR_B_IO;
+ config |= I8255_CTRL_B_IO;
if (!(s->io_bits & 0x0f0000))
- config |= CR_C_LO_IO;
+ config |= I8255_CTRL_C_LO_IO;
if (!(s->io_bits & 0xf00000))
- config |= CR_C_HI_IO;
- dio200_write8(dev, subpriv->ofs + 3, config);
+ config |= I8255_CTRL_C_HI_IO;
+ dio200_write8(dev, subpriv->ofs + I8255_CTRL_REG, config);
}
static int dio200_subdev_8255_bits(struct comedi_device *dev,
@@ -933,27 +804,25 @@ static int dio200_subdev_8255_bits(struct comedi_device *dev,
mask = comedi_dio_update_state(s, data);
if (mask) {
if (mask & 0xff)
- dio200_write8(dev, subpriv->ofs, s->state & 0xff);
+ dio200_write8(dev, subpriv->ofs + I8255_DATA_A_REG,
+ s->state & 0xff);
if (mask & 0xff00)
- dio200_write8(dev, subpriv->ofs + 1,
+ dio200_write8(dev, subpriv->ofs + I8255_DATA_B_REG,
(s->state >> 8) & 0xff);
if (mask & 0xff0000)
- dio200_write8(dev, subpriv->ofs + 2,
+ dio200_write8(dev, subpriv->ofs + I8255_DATA_C_REG,
(s->state >> 16) & 0xff);
}
- val = dio200_read8(dev, subpriv->ofs);
- val |= dio200_read8(dev, subpriv->ofs + 1) << 8;
- val |= dio200_read8(dev, subpriv->ofs + 2) << 16;
+ val = dio200_read8(dev, subpriv->ofs + I8255_DATA_A_REG);
+ val |= dio200_read8(dev, subpriv->ofs + I8255_DATA_B_REG) << 8;
+ val |= dio200_read8(dev, subpriv->ofs + I8255_DATA_C_REG) << 16;
data[1] = val;
return insn->n;
}
-/*
- * Handle 'insn_config' for an '8255' DIO subdevice.
- */
static int dio200_subdev_8255_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -981,11 +850,6 @@ static int dio200_subdev_8255_config(struct comedi_device *dev,
return insn->n;
}
-/*
- * This function initializes an '8255' DIO subdevice.
- *
- * offset is the offset to the 8255 chip.
- */
static int dio200_subdev_8255_init(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int offset)
@@ -1009,9 +873,6 @@ static int dio200_subdev_8255_init(struct comedi_device *dev,
return 0;
}
-/*
- * Handle 'insn_read' for a timer subdevice.
- */
static int dio200_subdev_timer_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -1024,9 +885,6 @@ static int dio200_subdev_timer_read(struct comedi_device *dev,
return n;
}
-/*
- * Reset timer subdevice.
- */
static void dio200_subdev_timer_reset(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -1037,9 +895,6 @@ static void dio200_subdev_timer_reset(struct comedi_device *dev,
dio200_write32(dev, DIO200_TS_CONFIG, clock);
}
-/*
- * Get timer subdevice clock source and period.
- */
static void dio200_subdev_timer_get_clock_src(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int *src,
@@ -1053,9 +908,6 @@ static void dio200_subdev_timer_get_clock_src(struct comedi_device *dev,
ts_clock_period[clk] : 0;
}
-/*
- * Set timer subdevice clock source.
- */
static int dio200_subdev_timer_set_clock_src(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int src)
@@ -1066,9 +918,6 @@ static int dio200_subdev_timer_set_clock_src(struct comedi_device *dev,
return 0;
}
-/*
- * Handle 'insn_config' for a timer subdevice.
- */
static int dio200_subdev_timer_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -1095,23 +944,6 @@ static int dio200_subdev_timer_config(struct comedi_device *dev,
return ret < 0 ? ret : insn->n;
}
-/*
- * This function initializes a timer subdevice.
- *
- * Uses the timestamp timer registers. There is only one timestamp timer.
- */
-static int dio200_subdev_timer_init(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- s->type = COMEDI_SUBD_TIMER;
- s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
- s->n_chan = 1;
- s->maxdata = 0xFFFFFFFF;
- s->insn_read = dio200_subdev_timer_read;
- s->insn_config = dio200_subdev_timer_config;
- return 0;
-}
-
void amplc_dio200_set_enhance(struct comedi_device *dev, unsigned char val)
{
dio200_write8(dev, DIO200_ENHANCE, val);
@@ -1121,65 +953,60 @@ EXPORT_SYMBOL_GPL(amplc_dio200_set_enhance);
int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq,
unsigned long req_irq_flags)
{
- const struct dio200_board *thisboard = comedi_board(dev);
- struct dio200_private *devpriv = dev->private;
- const struct dio200_layout *layout = dio200_board_layout(thisboard);
+ const struct dio200_board *board = dev->board_ptr;
struct comedi_subdevice *s;
- int sdx;
unsigned int n;
int ret;
- devpriv->intr_sd = -1;
-
- ret = comedi_alloc_subdevices(dev, layout->n_subdevs);
+ ret = comedi_alloc_subdevices(dev, board->n_subdevs);
if (ret)
return ret;
for (n = 0; n < dev->n_subdevices; n++) {
s = &dev->subdevices[n];
- switch (layout->sdtype[n]) {
+ switch (board->sdtype[n]) {
case sd_8254:
/* counter subdevice (8254) */
ret = dio200_subdev_8254_init(dev, s,
- layout->sdinfo[n]);
+ board->sdinfo[n]);
if (ret < 0)
return ret;
break;
case sd_8255:
/* digital i/o subdevice (8255) */
ret = dio200_subdev_8255_init(dev, s,
- layout->sdinfo[n]);
+ board->sdinfo[n]);
if (ret < 0)
return ret;
break;
case sd_intr:
/* 'INTERRUPT' subdevice */
- if (irq) {
+ if (irq && !dev->read_subdev) {
ret = dio200_subdev_intr_init(dev, s,
DIO200_INT_SCE,
- layout->sdinfo[n]
- );
+ board->sdinfo[n]);
if (ret < 0)
return ret;
- devpriv->intr_sd = n;
+ dev->read_subdev = s;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
break;
case sd_timer:
- ret = dio200_subdev_timer_init(dev, s);
- if (ret < 0)
- return ret;
+ s->type = COMEDI_SUBD_TIMER;
+ s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
+ s->n_chan = 1;
+ s->maxdata = 0xffffffff;
+ s->insn_read = dio200_subdev_timer_read;
+ s->insn_config = dio200_subdev_timer_config;
break;
default:
s->type = COMEDI_SUBD_UNUSED;
break;
}
}
- sdx = devpriv->intr_sd;
- if (sdx >= 0 && sdx < dev->n_subdevices)
- dev->read_subdev = &dev->subdevices[sdx];
- if (irq) {
+
+ if (irq && dev->read_subdev) {
if (request_irq(irq, dio200_interrupt, req_irq_flags,
dev->board_name, dev) >= 0) {
dev->irq = irq;
@@ -1193,15 +1020,6 @@ int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq,
}
EXPORT_SYMBOL_GPL(amplc_dio200_common_attach);
-void amplc_dio200_common_detach(struct comedi_device *dev)
-{
- if (dev->irq) {
- free_irq(dev->irq, dev);
- dev->irq = 0;
- }
-}
-EXPORT_SYMBOL_GPL(amplc_dio200_common_detach);
-
static int __init amplc_dio200_common_init(void)
{
return 0;
diff --git a/drivers/staging/comedi/drivers/amplc_dio200_pci.c b/drivers/staging/comedi/drivers/amplc_dio200_pci.c
index fbf05687347f..b83d1f5a8fb9 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200_pci.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200_pci.c
@@ -242,80 +242,70 @@ enum dio200_pci_model {
static const struct dio200_board dio200_pci_boards[] = {
[pci215_model] = {
- .name = "pci215",
- .bustype = pci_bustype,
- .mainbar = 2,
- .mainsize = DIO200_IO_SIZE,
- .layout = {
- .n_subdevs = 5,
- .sdtype = {sd_8255, sd_8255, sd_8254, sd_8254, sd_intr},
- .sdinfo = {0x00, 0x08, 0x10, 0x14, 0x3F},
- .has_int_sce = true,
- .has_clk_gat_sce = true,
+ .name = "pci215",
+ .mainbar = 2,
+ .n_subdevs = 5,
+ .sdtype = {
+ sd_8255, sd_8255, sd_8254, sd_8254, sd_intr
},
+ .sdinfo = { 0x00, 0x08, 0x10, 0x14, 0x3f },
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
},
[pci272_model] = {
- .name = "pci272",
- .bustype = pci_bustype,
- .mainbar = 2,
- .mainsize = DIO200_IO_SIZE,
- .layout = {
- .n_subdevs = 4,
- .sdtype = {sd_8255, sd_8255, sd_8255, sd_intr},
- .sdinfo = {0x00, 0x08, 0x10, 0x3F},
- .has_int_sce = true,
+ .name = "pci272",
+ .mainbar = 2,
+ .n_subdevs = 4,
+ .sdtype = {
+ sd_8255, sd_8255, sd_8255, sd_intr
},
+ .sdinfo = { 0x00, 0x08, 0x10, 0x3f },
+ .has_int_sce = true,
},
[pcie215_model] = {
- .name = "pcie215",
- .bustype = pci_bustype,
- .mainbar = 1,
- .mainshift = 3,
- .mainsize = DIO200_PCIE_IO_SIZE,
- .layout = {
- .n_subdevs = 8,
- .sdtype = {sd_8255, sd_none, sd_8255, sd_none,
- sd_8254, sd_8254, sd_timer, sd_intr},
- .sdinfo = {0x00, 0x00, 0x08, 0x00,
- 0x10, 0x14, 0x00, 0x3F},
- .has_int_sce = true,
- .has_clk_gat_sce = true,
- .has_enhancements = true,
+ .name = "pcie215",
+ .mainbar = 1,
+ .n_subdevs = 8,
+ .sdtype = {
+ sd_8255, sd_none, sd_8255, sd_none,
+ sd_8254, sd_8254, sd_timer, sd_intr
},
+ .sdinfo = {
+ 0x00, 0x00, 0x08, 0x00, 0x10, 0x14, 0x00, 0x3f
+ },
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
+ .is_pcie = true,
},
[pcie236_model] = {
- .name = "pcie236",
- .bustype = pci_bustype,
- .mainbar = 1,
- .mainshift = 3,
- .mainsize = DIO200_PCIE_IO_SIZE,
- .layout = {
- .n_subdevs = 8,
- .sdtype = {sd_8255, sd_none, sd_none, sd_none,
- sd_8254, sd_8254, sd_timer, sd_intr},
- .sdinfo = {0x00, 0x00, 0x00, 0x00,
- 0x10, 0x14, 0x00, 0x3F},
- .has_int_sce = true,
- .has_clk_gat_sce = true,
- .has_enhancements = true,
+ .name = "pcie236",
+ .mainbar = 1,
+ .n_subdevs = 8,
+ .sdtype = {
+ sd_8255, sd_none, sd_none, sd_none,
+ sd_8254, sd_8254, sd_timer, sd_intr
+ },
+ .sdinfo = {
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x14, 0x00, 0x3f
},
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
+ .is_pcie = true,
},
[pcie296_model] = {
- .name = "pcie296",
- .bustype = pci_bustype,
- .mainbar = 1,
- .mainshift = 3,
- .mainsize = DIO200_PCIE_IO_SIZE,
- .layout = {
- .n_subdevs = 8,
- .sdtype = {sd_8255, sd_8255, sd_8255, sd_8255,
- sd_8254, sd_8254, sd_timer, sd_intr},
- .sdinfo = {0x00, 0x04, 0x08, 0x0C,
- 0x10, 0x14, 0x00, 0x3F},
- .has_int_sce = true,
- .has_clk_gat_sce = true,
- .has_enhancements = true,
+ .name = "pcie296",
+ .mainbar = 1,
+ .n_subdevs = 8,
+ .sdtype = {
+ sd_8255, sd_8255, sd_8255, sd_8255,
+ sd_8254, sd_8254, sd_timer, sd_intr
+ },
+ .sdinfo = {
+ 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x00, 0x3f
},
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
+ .is_pcie = true,
},
};
@@ -358,34 +348,25 @@ static int dio200_pci_auto_attach(struct comedi_device *dev,
unsigned long context_model)
{
struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
- const struct dio200_board *thisboard = NULL;
- struct dio200_private *devpriv;
+ const struct dio200_board *board = NULL;
unsigned int bar;
int ret;
if (context_model < ARRAY_SIZE(dio200_pci_boards))
- thisboard = &dio200_pci_boards[context_model];
- if (!thisboard)
+ board = &dio200_pci_boards[context_model];
+ if (!board)
return -EINVAL;
- dev->board_ptr = thisboard;
- dev->board_name = thisboard->name;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
dev_info(dev->class_dev, "%s: attach pci %s (%s)\n",
dev->driver->driver_name, pci_name(pci_dev), dev->board_name);
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
ret = comedi_pci_enable(dev);
if (ret)
return ret;
- bar = thisboard->mainbar;
- if (pci_resource_len(pci_dev, bar) < thisboard->mainsize) {
- dev_err(dev->class_dev, "error! PCI region size too small!\n");
- return -EINVAL;
- }
+ bar = board->mainbar;
if (pci_resource_flags(pci_dev, bar) & IORESOURCE_MEM) {
dev->mmio = pci_ioremap_bar(pci_dev, bar);
if (!dev->mmio) {
@@ -396,33 +377,21 @@ static int dio200_pci_auto_attach(struct comedi_device *dev,
} else {
dev->iobase = pci_resource_start(pci_dev, bar);
}
- switch (context_model) {
- case pcie215_model:
- case pcie236_model:
- case pcie296_model:
+
+ if (board->is_pcie) {
ret = dio200_pcie_board_setup(dev);
if (ret < 0)
return ret;
- break;
- default:
- break;
}
- return amplc_dio200_common_attach(dev, pci_dev->irq, IRQF_SHARED);
-}
-static void dio200_pci_detach(struct comedi_device *dev)
-{
- amplc_dio200_common_detach(dev);
- if (dev->mmio)
- iounmap(dev->mmio);
- comedi_pci_disable(dev);
+ return amplc_dio200_common_attach(dev, pci_dev->irq, IRQF_SHARED);
}
static struct comedi_driver dio200_pci_comedi_driver = {
- .driver_name = "amplc_dio200_pci",
- .module = THIS_MODULE,
- .auto_attach = dio200_pci_auto_attach,
- .detach = dio200_pci_detach,
+ .driver_name = "amplc_dio200_pci",
+ .module = THIS_MODULE,
+ .auto_attach = dio200_pci_auto_attach,
+ .detach = comedi_pci_detach,
};
static const struct pci_device_id dio200_pci_table[] = {
@@ -443,10 +412,10 @@ static int dio200_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
}
static struct pci_driver dio200_pci_pci_driver = {
- .name = "amplc_dio200_pci",
- .id_table = dio200_pci_table,
- .probe = dio200_pci_probe,
- .remove = comedi_pci_auto_unconfig,
+ .name = "amplc_dio200_pci",
+ .id_table = dio200_pci_table,
+ .probe = dio200_pci_probe,
+ .remove = comedi_pci_auto_unconfig,
};
module_comedi_pci_driver(dio200_pci_comedi_driver, dio200_pci_pci_driver);
diff --git a/drivers/staging/comedi/drivers/amplc_pc236_common.c b/drivers/staging/comedi/drivers/amplc_pc236_common.c
index 18e237cca419..963c5d868b81 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236_common.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236_common.c
@@ -29,7 +29,7 @@
static void pc236_intr_update(struct comedi_device *dev, bool enable)
{
- const struct pc236_board *thisboard = comedi_board(dev);
+ const struct pc236_board *thisboard = dev->board_ptr;
struct pc236_private *devpriv = dev->private;
unsigned long flags;
@@ -49,7 +49,7 @@ static void pc236_intr_update(struct comedi_device *dev, bool enable)
*/
static bool pc236_intr_check(struct comedi_device *dev)
{
- const struct pc236_board *thisboard = comedi_board(dev);
+ const struct pc236_board *thisboard = dev->board_ptr;
struct pc236_private *devpriv = dev->private;
bool retval = false;
unsigned long flags;
@@ -94,9 +94,6 @@ static int pc236_intr_cmdtest(struct comedi_device *dev,
/* Step 2a : make sure trigger sources are unique */
/* Step 2b : and mutually compatible */
- if (err)
- return 2;
-
/* Step 3: check it arguments are trivially valid */
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
@@ -108,10 +105,9 @@ static int pc236_intr_cmdtest(struct comedi_device *dev,
if (err)
return 3;
- /* step 4: ignored */
+ /* Step 4: fix up any arguments */
- if (err)
- return 4;
+ /* Step 5: check channel list if it exists */
return 0;
}
@@ -160,7 +156,7 @@ int amplc_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);
+ ret = subdev_8255_init(dev, s, NULL, 0x00);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index 45aba1f950fc..3bbbb57f19d6 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -1,102 +1,106 @@
/*
- comedi/drivers/amplc_pci224.c
- Driver for Amplicon PCI224 and PCI234 AO boards.
-
- Copyright (C) 2005 MEV Ltd. <http://www.mev.co.uk/>
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1998,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.
+ * comedi/drivers/amplc_pci224.c
+ * Driver for Amplicon PCI224 and PCI234 AO boards.
+ *
+ * Copyright (C) 2005 MEV Ltd. <http://www.mev.co.uk/>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1998,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 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: amplc_pci224
-Description: Amplicon PCI224, PCI234
-Author: Ian Abbott <abbotti@mev.co.uk>
-Devices: [Amplicon] PCI224 (amplc_pci224 or pci224),
- PCI234 (amplc_pci224 or pci234)
-Updated: Wed, 22 Oct 2008 12:25:08 +0100
-Status: works, but see caveats
-
-Supports:
-
- - ao_insn read/write
- - ao_do_cmd mode with the following sources:
-
- - start_src TRIG_INT TRIG_EXT
- - scan_begin_src TRIG_TIMER TRIG_EXT
- - convert_src TRIG_NOW
- - scan_end_src TRIG_COUNT
- - stop_src TRIG_COUNT TRIG_EXT TRIG_NONE
-
- The channel list must contain at least one channel with no repeated
- channels. The scan end count must equal the number of channels in
- the channel list.
-
- There is only one external trigger source so only one of start_src,
- scan_begin_src or stop_src may use TRIG_EXT.
-
-Configuration options - PCI224:
- [0] - PCI bus of device (optional).
- [1] - PCI slot of device (optional).
- If bus/slot is not specified, the first available PCI device
- will be used.
- [2] - Select available ranges according to jumper LK1. All channels
- are set to the same range:
- 0=Jumper position 1-2 (factory default), 4 software-selectable
- internal voltage references, giving 4 bipolar and 4 unipolar
- ranges:
- [-10V,+10V], [-5V,+5V], [-2.5V,+2.5V], [-1.25V,+1.25V],
- [0,+10V], [0,+5V], [0,+2.5V], [0,1.25V].
- 1=Jumper position 2-3, 1 external voltage reference, giving
- 1 bipolar and 1 unipolar range:
- [-Vext,+Vext], [0,+Vext].
-
-Configuration options - PCI234:
- [0] - PCI bus of device (optional).
- [1] - PCI slot of device (optional).
- If bus/slot is not specified, the first available PCI device
- will be used.
- [2] - Select internal or external voltage reference according to
- jumper LK1. This affects all channels:
- 0=Jumper position 1-2 (factory default), Vref=5V internal.
- 1=Jumper position 2-3, Vref=Vext external.
- [3] - Select channel 0 range according to jumper LK2:
- 0=Jumper position 2-3 (factory default), range [-2*Vref,+2*Vref]
- (10V bipolar when options[2]=0).
- 1=Jumper position 1-2, range [-Vref,+Vref]
- (5V bipolar when options[2]=0).
- [4] - Select channel 1 range according to jumper LK3: cf. options[3].
- [5] - Select channel 2 range according to jumper LK4: cf. options[3].
- [6] - Select channel 3 range according to jumper LK5: cf. options[3].
-
-Passing a zero for an option is the same as leaving it unspecified.
-
-Caveats:
-
- 1) All channels on the PCI224 share the same range. Any change to the
- range as a result of insn_write or a streaming command will affect
- the output voltages of all channels, including those not specified
- by the instruction or command.
-
- 2) For the analog output command, the first scan may be triggered
- falsely at the start of acquisition. This occurs when the DAC scan
- trigger source is switched from 'none' to 'timer' (scan_begin_src =
- TRIG_TIMER) or 'external' (scan_begin_src == TRIG_EXT) at the start
- of acquisition and the trigger source is at logic level 1 at the
- time of the switch. This is very likely for TRIG_TIMER. For
- TRIG_EXT, it depends on the state of the external line and whether
- the CR_INVERT flag has been set. The remaining scans are triggered
- correctly.
-*/
+ * Driver: amplc_pci224
+ * Description: Amplicon PCI224, PCI234
+ * Author: Ian Abbott <abbotti@mev.co.uk>
+ * Devices: [Amplicon] PCI224 (amplc_pci224), PCI234
+ * Updated: Thu, 31 Jul 2014 11:08:03 +0000
+ * Status: works, but see caveats
+ *
+ * Supports:
+ *
+ * - ao_insn read/write
+ * - ao_do_cmd mode with the following sources:
+ *
+ * - start_src TRIG_INT TRIG_EXT
+ * - scan_begin_src TRIG_TIMER TRIG_EXT
+ * - convert_src TRIG_NOW
+ * - scan_end_src TRIG_COUNT
+ * - stop_src TRIG_COUNT TRIG_EXT TRIG_NONE
+ *
+ * The channel list must contain at least one channel with no repeated
+ * channels. The scan end count must equal the number of channels in
+ * the channel list.
+ *
+ * There is only one external trigger source so only one of start_src,
+ * scan_begin_src or stop_src may use TRIG_EXT.
+ *
+ * Configuration options:
+ * none
+ *
+ * Manual configuration of PCI cards is not supported; they are configured
+ * automatically.
+ *
+ * Output range selection - PCI224:
+ *
+ * Output ranges on PCI224 are partly software-selectable and partly
+ * hardware-selectable according to jumper LK1. All channels are set
+ * to the same range:
+ *
+ * - LK1 position 1-2 (factory default) corresponds to the following
+ * comedi ranges:
+ *
+ * 0: [-10V,+10V]; 1: [-5V,+5V]; 2: [-2.5V,+2.5V], 3: [-1.25V,+1.25V],
+ * 4: [0,+10V], 5: [0,+5V], 6: [0,+2.5V], 7: [0,+1.25V]
+ *
+ * - LK1 position 2-3 corresponds to the following Comedi ranges, using
+ * an external voltage reference:
+ *
+ * 0: [-Vext,+Vext],
+ * 1: [0,+Vext]
+ *
+ * Output range selection - PCI234:
+ *
+ * Output ranges on PCI234 are hardware-selectable according to jumper
+ * LK1 which affects all channels, and jumpers LK2, LK3, LK4 and LK5
+ * which affect channels 0, 1, 2 and 3 individually. LK1 chooses between
+ * an internal 5V reference and an external voltage reference (Vext).
+ * LK2/3/4/5 choose (per channel) to double the reference or not according
+ * to the following table:
+ *
+ * LK1 position LK2/3/4/5 pos Comedi range
+ * ------------- ------------- --------------
+ * 2-3 (factory) 1-2 (factory) 0: [-10V,+10V]
+ * 2-3 (factory) 2-3 1: [-5V,+5V]
+ * 1-2 1-2 (factory) 2: [-2*Vext,+2*Vext]
+ * 1-2 2-3 3: [-Vext,+Vext]
+ *
+ * Caveats:
+ *
+ * 1) All channels on the PCI224 share the same range. Any change to the
+ * range as a result of insn_write or a streaming command will affect
+ * the output voltages of all channels, including those not specified
+ * by the instruction or command.
+ *
+ * 2) For the analog output command, the first scan may be triggered
+ * falsely at the start of acquisition. This occurs when the DAC scan
+ * trigger source is switched from 'none' to 'timer' (scan_begin_src =
+ * TRIG_TIMER) or 'external' (scan_begin_src == TRIG_EXT) at the start
+ * of acquisition and the trigger source is at logic level 1 at the
+ * time of the switch. This is very likely for TRIG_TIMER. For
+ * TRIG_EXT, it depends on the state of the external line and whether
+ * the CR_INVERT flag has been set. The remaining scans are triggered
+ * correctly.
+ */
#include <linux/module.h>
#include <linux/pci.h>
@@ -109,13 +113,6 @@ Caveats:
#include "8253.h"
/*
- * PCI IDs.
- */
-#define PCI_DEVICE_ID_AMPLICON_PCI224 0x0007
-#define PCI_DEVICE_ID_AMPLICON_PCI234 0x0008
-#define PCI_DEVICE_ID_INVALID 0xffff
-
-/*
* PCI224/234 i/o space 1 (PCIBAR2) registers.
*/
#define PCI224_Z2_CT0 0x14 /* 82C54 counter/timer 0 */
@@ -261,9 +258,17 @@ Caveats:
* Range tables.
*/
-/* The software selectable internal ranges for PCI224 (option[2] == 0). */
-static const struct comedi_lrange range_pci224_internal = {
- 8, {
+/*
+ * The ranges for PCI224.
+ *
+ * These are partly hardware-selectable by jumper LK1 and partly
+ * software-selectable.
+ *
+ * All channels share the same hardware range.
+ */
+static const struct comedi_lrange range_pci224 = {
+ 10, {
+ /* jumper LK1 in position 1-2 (factory default) */
BIP_RANGE(10),
BIP_RANGE(5),
BIP_RANGE(2.5),
@@ -271,11 +276,15 @@ static const struct comedi_lrange range_pci224_internal = {
UNI_RANGE(10),
UNI_RANGE(5),
UNI_RANGE(2.5),
- UNI_RANGE(1.25)
+ UNI_RANGE(1.25),
+ /* jumper LK1 in position 2-3 */
+ RANGE_ext(-1, 1), /* bipolar [-Vext,+Vext] */
+ RANGE_ext(0, 1), /* unipolar [0,+Vext] */
}
};
-static const unsigned short hwrange_pci224_internal[8] = {
+static const unsigned short hwrange_pci224[10] = {
+ /* jumper LK1 in position 1-2 (factory default) */
PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_10,
PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_5,
PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_2_5,
@@ -284,87 +293,87 @@ static const unsigned short hwrange_pci224_internal[8] = {
PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_5,
PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_2_5,
PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_1_25,
-};
-
-/* The software selectable external ranges for PCI224 (option[2] == 1). */
-static const struct comedi_lrange range_pci224_external = {
- 2, {
- RANGE_ext(-1, 1), /* bipolar [-Vref,+Vref] */
- RANGE_ext(0, 1) /* unipolar [0,+Vref] */
- }
-};
-
-static const unsigned short hwrange_pci224_external[2] = {
+ /* jumper LK1 in position 2-3 */
PCI224_DACCON_POLAR_BI,
PCI224_DACCON_POLAR_UNI,
};
-/* The hardware selectable Vref*2 external range for PCI234
- * (option[2] == 1, option[3+n] == 0). */
-static const struct comedi_lrange range_pci234_ext2 = {
- 1, {
- RANGE_ext(-2, 2)
- }
+/* Used to check all channels set to the same range on PCI224. */
+static const unsigned char range_check_pci224[10] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
};
-/* The hardware selectable Vref external range for PCI234
- * (option[2] == 1, option[3+n] == 1). */
-static const struct comedi_lrange range_pci234_ext = {
- 1, {
- RANGE_ext(-1, 1)
+/*
+ * The ranges for PCI234.
+ *
+ * These are all hardware-selectable by jumper LK1 affecting all channels,
+ * and jumpers LK2, LK3, LK4 and LK5 affecting channels 0, 1, 2 and 3
+ * individually.
+ */
+static const struct comedi_lrange range_pci234 = {
+ 4, {
+ /* LK1: 1-2 (fact def), LK2/3/4/5: 2-3 (fac def) */
+ BIP_RANGE(10),
+ /* LK1: 1-2 (fact def), LK2/3/4/5: 1-2 */
+ BIP_RANGE(5),
+ /* LK1: 2-3, LK2/3/4/5: 2-3 (fac def) */
+ RANGE_ext(-2, 2), /* bipolar [-2*Vext,+2*Vext] */
+ /* LK1: 2-3, LK2/3/4/5: 1-2 */
+ RANGE_ext(-1, 1), /* bipolar [-Vext,+Vext] */
}
};
-/* This serves for all the PCI234 ranges. */
-static const unsigned short hwrange_pci234[1] = {
- PCI224_DACCON_POLAR_BI, /* bipolar - hardware ignores it! */
+/* N.B. PCI234 ignores the polarity bit, but software uses it. */
+static const unsigned short hwrange_pci234[4] = {
+ PCI224_DACCON_POLAR_BI,
+ PCI224_DACCON_POLAR_BI,
+ PCI224_DACCON_POLAR_BI,
+ PCI224_DACCON_POLAR_BI,
+};
+
+/* Used to check all channels use same LK1 setting on PCI234. */
+static const unsigned char range_check_pci234[4] = {
+ 0, 0, 1, 1,
};
/*
* Board descriptions.
*/
-enum pci224_model { any_model, pci224_model, pci234_model };
+enum pci224_model { pci224_model, pci234_model };
struct pci224_board {
const char *name;
- unsigned short devid;
- enum pci224_model model;
unsigned int ao_chans;
unsigned int ao_bits;
+ const struct comedi_lrange *ao_range;
+ const unsigned short *ao_hwrange;
+ const unsigned char *ao_range_check;
};
static const struct pci224_board pci224_boards[] = {
- {
- .name = "pci224",
- .devid = PCI_DEVICE_ID_AMPLICON_PCI224,
- .model = pci224_model,
- .ao_chans = 16,
- .ao_bits = 12,
- },
- {
- .name = "pci234",
- .devid = PCI_DEVICE_ID_AMPLICON_PCI234,
- .model = pci234_model,
- .ao_chans = 4,
- .ao_bits = 16,
- },
- {
- .name = "amplc_pci224",
- .devid = PCI_DEVICE_ID_INVALID,
- .model = any_model, /* wildcard */
- },
+ [pci224_model] = {
+ .name = "pci224",
+ .ao_chans = 16,
+ .ao_bits = 12,
+ .ao_range = &range_pci224,
+ .ao_hwrange = &hwrange_pci224[0],
+ .ao_range_check = &range_check_pci224[0],
+ },
+ [pci234_model] = {
+ .name = "pci234",
+ .ao_chans = 4,
+ .ao_bits = 16,
+ .ao_range = &range_pci234,
+ .ao_hwrange = &hwrange_pci234[0],
+ .ao_range_check = &range_check_pci234[0],
+ },
};
-/* this structure is for data unique to this hardware driver. If
- several hardware drivers keep similar information in this structure,
- feel free to suggest moving the variable to the struct comedi_device struct. */
struct pci224_private {
- const unsigned short *hwrange;
unsigned long iobase1;
unsigned long state;
- spinlock_t ao_spinlock;
- unsigned int *ao_readback;
+ spinlock_t ao_spinlock; /* spinlock for AO command handling */
unsigned short *ao_scan_vals;
unsigned char *ao_scan_order;
int intr_cpuid;
@@ -384,18 +393,16 @@ static void
pci224_ao_set_data(struct comedi_device *dev, int chan, int range,
unsigned int data)
{
- const struct pci224_board *thisboard = comedi_board(dev);
+ const struct pci224_board *thisboard = dev->board_ptr;
struct pci224_private *devpriv = dev->private;
unsigned short mangled;
- /* Store unmangled data for readback. */
- devpriv->ao_readback[chan] = data;
/* Enable the channel. */
outw(1 << chan, dev->iobase + PCI224_DACCEN);
/* Set range and reset FIFO. */
- devpriv->daccon = COMBINE(devpriv->daccon, devpriv->hwrange[range],
- (PCI224_DACCON_POLAR_MASK |
- PCI224_DACCON_VREF_MASK));
+ devpriv->daccon = COMBINE(devpriv->daccon, thisboard->ao_hwrange[range],
+ PCI224_DACCON_POLAR_MASK |
+ PCI224_DACCON_VREF_MASK);
outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
dev->iobase + PCI224_DACCON);
/*
@@ -414,51 +421,23 @@ pci224_ao_set_data(struct comedi_device *dev, int chan, int range,
inw(dev->iobase + PCI224_SOFTTRIG);
}
-/*
- * 'insn_write' function for AO subdevice.
- */
-static int
-pci224_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int pci224_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int val = s->readback[chan];
int i;
- int chan, range;
-
- /* Unpack channel and range. */
- chan = CR_CHAN(insn->chanspec);
- range = CR_RANGE(insn->chanspec);
-
- /* Writing a list of values to an AO channel is probably not
- * very useful, but that's how the interface is defined. */
- for (i = 0; i < insn->n; i++)
- pci224_ao_set_data(dev, chan, range, data[i]);
-
- return i;
-}
-
-/*
- * 'insn_read' function for AO subdevice.
- *
- * N.B. The value read will not be valid if the DAC channel has
- * never been written successfully since the device was attached
- * or since the channel has been used by an AO streaming write
- * command.
- */
-static int
-pci224_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct pci224_private *devpriv = dev->private;
- int i;
- int chan;
-
- chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+ pci224_ao_set_data(dev, chan, range, val);
+ }
+ s->readback[chan] = val;
- return i;
+ return insn->n;
}
/*
@@ -496,11 +475,10 @@ static void pci224_ao_stop(struct comedi_device *dev,
spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
/* Reconfigure DAC for insn_write usage. */
outw(0, dev->iobase + PCI224_DACCEN); /* Disable channels. */
- devpriv->daccon = COMBINE(devpriv->daccon,
- PCI224_DACCON_TRIG_SW |
- PCI224_DACCON_FIFOINTR_EMPTY,
- PCI224_DACCON_TRIG_MASK |
- PCI224_DACCON_FIFOINTR_MASK);
+ devpriv->daccon =
+ COMBINE(devpriv->daccon,
+ PCI224_DACCON_TRIG_SW | PCI224_DACCON_FIFOINTR_EMPTY,
+ PCI224_DACCON_TRIG_MASK | PCI224_DACCON_FIFOINTR_MASK);
outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
dev->iobase + PCI224_DACCON);
}
@@ -516,21 +494,16 @@ static void pci224_ao_start(struct comedi_device *dev,
unsigned long flags;
set_bit(AO_CMD_STARTED, &devpriv->state);
- if (cmd->stop_src == TRIG_COUNT && devpriv->ao_stop_count == 0) {
- /* An empty acquisition! */
- s->async->events |= COMEDI_CB_EOA;
- cfc_handle_events(dev, s);
- } else {
- /* Enable interrupts. */
- spin_lock_irqsave(&devpriv->ao_spinlock, flags);
- if (cmd->stop_src == TRIG_EXT)
- devpriv->intsce = PCI224_INTR_EXT | PCI224_INTR_DAC;
- else
- devpriv->intsce = PCI224_INTR_DAC;
- outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE);
- spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
- }
+ /* Enable interrupts. */
+ spin_lock_irqsave(&devpriv->ao_spinlock, flags);
+ if (cmd->stop_src == TRIG_EXT)
+ devpriv->intsce = PCI224_INTR_EXT | PCI224_INTR_DAC;
+ else
+ devpriv->intsce = PCI224_INTR_DAC;
+
+ outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE);
+ spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
}
/*
@@ -553,7 +526,6 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev,
/* Fixed number of scans. */
if (num_scans > devpriv->ao_stop_count)
num_scans = devpriv->ao_stop_count;
-
}
/* Determine how much room is in the FIFO (in samples). */
@@ -561,7 +533,8 @@ 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 (cmd->stop_src == TRIG_COUNT && devpriv->ao_stop_count == 0) {
+ if (cmd->stop_src == TRIG_COUNT &&
+ devpriv->ao_stop_count == 0) {
/* FIFO empty at end of counted acquisition. */
s->async->events |= COMEDI_CB_EOA;
cfc_handle_events(dev, s);
@@ -639,10 +612,9 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev,
trig = PCI224_DACCON_TRIG_EXTN;
else
trig = PCI224_DACCON_TRIG_EXTP;
-
}
- devpriv->daccon = COMBINE(devpriv->daccon, trig,
- PCI224_DACCON_TRIG_MASK);
+ devpriv->daccon =
+ COMBINE(devpriv->daccon, trig, PCI224_DACCON_TRIG_MASK);
outw(devpriv->daccon, dev->iobase + PCI224_DACCON);
}
@@ -668,13 +640,14 @@ 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]);
+ const struct pci224_board *thisboard = dev->board_ptr;
+ unsigned int range_check_0;
unsigned int chan_mask = 0;
int i;
+ range_check_0 = thisboard->ao_range_check[CR_RANGE(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]);
if (chan_mask & (1 << chan)) {
dev_dbg(dev->class_dev,
@@ -682,11 +655,12 @@ static int pci224_ao_check_chanlist(struct comedi_device *dev,
__func__);
return -EINVAL;
}
- chan_mask |= (1 << chan);
+ chan_mask |= 1 << chan;
- if (range != range0) {
+ if (thisboard->ao_range_check[CR_RANGE(cmd->chanlist[i])] !=
+ range_check_0) {
dev_dbg(dev->class_dev,
- "%s: entries in chanlist must all have the same range index\n",
+ "%s: entries in chanlist have incompatible ranges\n",
__func__);
return -EINVAL;
}
@@ -714,11 +688,11 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT);
err |= cfc_check_trigger_src(&cmd->scan_begin_src,
- TRIG_EXT | TRIG_TIMER);
+ TRIG_EXT | TRIG_TIMER);
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_EXT | TRIG_NONE);
+ TRIG_COUNT | TRIG_EXT | TRIG_NONE);
if (err)
return 1;
@@ -756,13 +730,13 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
break;
case TRIG_EXT:
/* Force to external trigger 0. */
- if ((cmd->start_arg & ~CR_FLAGS_MASK) != 0) {
- cmd->start_arg = COMBINE(cmd->start_arg, 0,
- ~CR_FLAGS_MASK);
+ if (cmd->start_arg & ~CR_FLAGS_MASK) {
+ cmd->start_arg =
+ COMBINE(cmd->start_arg, 0, ~CR_FLAGS_MASK);
err |= -EINVAL;
}
/* The only flag allowed is CR_EDGE, which is ignored. */
- if ((cmd->start_arg & CR_FLAGS_MASK & ~CR_EDGE) != 0) {
+ if (cmd->start_arg & CR_FLAGS_MASK & ~CR_EDGE) {
cmd->start_arg = COMBINE(cmd->start_arg, 0,
CR_FLAGS_MASK & ~CR_EDGE);
err |= -EINVAL;
@@ -782,17 +756,17 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
break;
case TRIG_EXT:
/* Force to external trigger 0. */
- if ((cmd->scan_begin_arg & ~CR_FLAGS_MASK) != 0) {
- cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
- ~CR_FLAGS_MASK);
+ if (cmd->scan_begin_arg & ~CR_FLAGS_MASK) {
+ cmd->scan_begin_arg =
+ COMBINE(cmd->scan_begin_arg, 0, ~CR_FLAGS_MASK);
err |= -EINVAL;
}
/* Only allow flags CR_EDGE and CR_INVERT. Ignore CR_EDGE. */
- if ((cmd->scan_begin_arg & CR_FLAGS_MASK &
- ~(CR_EDGE | CR_INVERT)) != 0) {
- cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
- CR_FLAGS_MASK &
- ~(CR_EDGE | CR_INVERT));
+ if (cmd->scan_begin_arg & CR_FLAGS_MASK &
+ ~(CR_EDGE | CR_INVERT)) {
+ cmd->scan_begin_arg =
+ COMBINE(cmd->scan_begin_arg, 0,
+ CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT));
err |= -EINVAL;
}
break;
@@ -803,19 +777,19 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
switch (cmd->stop_src) {
case TRIG_COUNT:
- /* Any count allowed. */
+ err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
break;
case TRIG_EXT:
/* Force to external trigger 0. */
- if ((cmd->stop_arg & ~CR_FLAGS_MASK) != 0) {
- cmd->stop_arg = COMBINE(cmd->stop_arg, 0,
- ~CR_FLAGS_MASK);
+ if (cmd->stop_arg & ~CR_FLAGS_MASK) {
+ cmd->stop_arg =
+ COMBINE(cmd->stop_arg, 0, ~CR_FLAGS_MASK);
err |= -EINVAL;
}
/* The only flag allowed is CR_EDGE, which is ignored. */
- if ((cmd->stop_arg & CR_FLAGS_MASK & ~CR_EDGE) != 0) {
- cmd->stop_arg = COMBINE(cmd->stop_arg, 0,
- CR_FLAGS_MASK & ~CR_EDGE);
+ if (cmd->stop_arg & CR_FLAGS_MASK & ~CR_EDGE) {
+ cmd->stop_arg =
+ COMBINE(cmd->stop_arg, 0, CR_FLAGS_MASK & ~CR_EDGE);
}
break;
case TRIG_NONE:
@@ -880,6 +854,7 @@ static void pci224_ao_start_pacer(struct comedi_device *dev,
static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ const struct pci224_board *thisboard = dev->board_ptr;
struct pci224_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
int range;
@@ -903,7 +878,6 @@ static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
for (j = 0; j < cmd->chanlist_len; j++) {
if (CR_CHAN(cmd->chanlist[j]) < ch)
rank++;
-
}
devpriv->ao_scan_order[rank] = i;
}
@@ -922,14 +896,12 @@ static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
*
* N.B. DAC FIFO interrupts are currently disabled.
*/
- devpriv->daccon = COMBINE(devpriv->daccon,
- (devpriv->
- hwrange[range] | PCI224_DACCON_TRIG_NONE |
- PCI224_DACCON_FIFOINTR_NHALF),
- (PCI224_DACCON_POLAR_MASK |
- PCI224_DACCON_VREF_MASK |
- PCI224_DACCON_TRIG_MASK |
- PCI224_DACCON_FIFOINTR_MASK));
+ devpriv->daccon =
+ COMBINE(devpriv->daccon,
+ thisboard->ao_hwrange[range] | PCI224_DACCON_TRIG_NONE |
+ PCI224_DACCON_FIFOINTR_NHALF,
+ PCI224_DACCON_POLAR_MASK | PCI224_DACCON_VREF_MASK |
+ PCI224_DACCON_TRIG_MASK | PCI224_DACCON_FIFOINTR_MASK);
outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
dev->iobase + PCI224_DACCON);
@@ -974,8 +946,7 @@ static void
pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
void *data, unsigned int num_bytes, unsigned int chan_index)
{
- const struct pci224_board *thisboard = comedi_board(dev);
- struct pci224_private *devpriv = dev->private;
+ const struct pci224_board *thisboard = dev->board_ptr;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned short *array = data;
unsigned int length = num_bytes / sizeof(*array);
@@ -986,7 +957,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(cmd->chanlist[0])] &
+ if ((thisboard->ao_hwrange[CR_RANGE(cmd->chanlist[0])] &
PCI224_DACCON_POLAR_MASK) == PCI224_DACCON_POLAR_UNI) {
/* Unipolar */
offset = 0;
@@ -997,7 +968,6 @@ pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
/* Munge the data. */
for (i = 0; i < length; i++)
array[i] = (array[i] << shift) - offset;
-
}
/*
@@ -1025,7 +995,7 @@ static irqreturn_t pci224_interrupt(int irq, void *d)
devpriv->intr_running = 1;
devpriv->intr_cpuid = THISCPU;
spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
- if (valid_intstat != 0) {
+ if (valid_intstat) {
cmd = &s->async->cmd;
if (valid_intstat & PCI224_INTR_EXT) {
devpriv->intsce &= ~PCI224_INTR_EXT;
@@ -1033,11 +1003,9 @@ static irqreturn_t pci224_interrupt(int irq, void *d)
pci224_ao_start(dev, s);
else if (cmd->stop_src == TRIG_EXT)
pci224_ao_stop(dev, s);
-
}
if (valid_intstat & PCI224_INTR_DAC)
pci224_ao_handle_fifo(dev, s);
-
}
/* Reenable interrupt sources. */
spin_lock_irqsave(&devpriv->ao_spinlock, flags);
@@ -1051,77 +1019,32 @@ static irqreturn_t pci224_interrupt(int irq, void *d)
return IRQ_RETVAL(retval);
}
-/*
- * This function looks for a board matching the supplied PCI device.
- */
-static const struct pci224_board
-*pci224_find_pci_board(struct pci_dev *pci_dev)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pci224_boards); i++)
- if (pci_dev->device == pci224_boards[i].devid)
- return &pci224_boards[i];
- return NULL;
-}
-
-/*
- * This function looks for a PCI device matching the requested board name,
- * bus and slot.
- */
-static struct pci_dev *pci224_find_pci_dev(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- const struct pci224_board *thisboard = comedi_board(dev);
- struct pci_dev *pci_dev = NULL;
- int bus = it->options[0];
- int slot = it->options[1];
-
- for_each_pci_dev(pci_dev) {
- if (bus || slot) {
- if (bus != pci_dev->bus->number ||
- slot != PCI_SLOT(pci_dev->devfn))
- continue;
- }
- if (pci_dev->vendor != PCI_VENDOR_ID_AMPLICON)
- continue;
-
- if (thisboard->model == any_model) {
- /* Match any supported model. */
- const struct pci224_board *board_ptr;
-
- board_ptr = pci224_find_pci_board(pci_dev);
- if (board_ptr == NULL)
- continue;
- /* Change board_ptr to matched board. */
- dev->board_ptr = board_ptr;
- } else {
- /* Match specific model name. */
- if (thisboard->devid != pci_dev->device)
- continue;
- }
- return pci_dev;
- }
- dev_err(dev->class_dev,
- "No supported board found! (req. bus %d, slot %d)\n",
- bus, slot);
- return NULL;
-}
-
-/*
- * Common part of attach and auto_attach.
- */
-static int pci224_attach_common(struct comedi_device *dev,
- struct pci_dev *pci_dev, int *options)
+static int
+pci224_auto_attach(struct comedi_device *dev, unsigned long context_model)
{
- const struct pci224_board *thisboard = comedi_board(dev);
- struct pci224_private *devpriv = dev->private;
+ struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
+ const struct pci224_board *thisboard = NULL;
+ struct pci224_private *devpriv;
struct comedi_subdevice *s;
unsigned int irq;
- unsigned n;
int ret;
- comedi_set_hw_dev(dev, &pci_dev->dev);
+ if (context_model < ARRAY_SIZE(pci224_boards))
+ thisboard = &pci224_boards[context_model];
+ if (!thisboard || !thisboard->name) {
+ dev_err(dev->class_dev,
+ "amplc_pci224: BUG! cannot determine board type!\n");
+ return -EINVAL;
+ }
+ dev->board_ptr = thisboard;
+ dev->board_name = thisboard->name;
+
+ dev_info(dev->class_dev, "amplc_pci224: attach pci %s - %s\n",
+ pci_name(pci_dev), dev->board_name);
+
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+ if (!devpriv)
+ return -ENOMEM;
ret = comedi_pci_enable(dev);
if (ret)
@@ -1133,13 +1056,6 @@ static int pci224_attach_common(struct comedi_device *dev,
dev->iobase = pci_resource_start(pci_dev, 3);
irq = pci_dev->irq;
- /* Allocate readback buffer for AO channels. */
- devpriv->ao_readback = kmalloc(sizeof(devpriv->ao_readback[0]) *
- thisboard->ao_chans, GFP_KERNEL);
- if (!devpriv->ao_readback)
- return -ENOMEM;
-
-
/* Allocate buffer to hold values for AO channel scan. */
devpriv->ao_scan_vals = kmalloc(sizeof(devpriv->ao_scan_vals[0]) *
thisboard->ao_chans, GFP_KERNEL);
@@ -1162,9 +1078,8 @@ static int pci224_attach_common(struct comedi_device *dev,
outw(PCI224_DACCON_GLOBALRESET, dev->iobase + PCI224_DACCON);
outw(0, dev->iobase + PCI224_DACCEN);
outw(0, dev->iobase + PCI224_FIFOSIZ);
- devpriv->daccon = (PCI224_DACCON_TRIG_SW | PCI224_DACCON_POLAR_BI |
- PCI224_DACCON_FIFOENAB |
- PCI224_DACCON_FIFOINTR_EMPTY);
+ devpriv->daccon = PCI224_DACCON_TRIG_SW | PCI224_DACCON_POLAR_BI |
+ PCI224_DACCON_FIFOENAB | PCI224_DACCON_FIFOINTR_EMPTY;
outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
dev->iobase + PCI224_DACCON);
@@ -1178,71 +1093,19 @@ static int pci224_attach_common(struct comedi_device *dev,
s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
s->n_chan = thisboard->ao_chans;
s->maxdata = (1 << thisboard->ao_bits) - 1;
- s->insn_write = &pci224_ao_insn_write;
- s->insn_read = &pci224_ao_insn_read;
+ s->range_table = thisboard->ao_range;
+ s->insn_write = pci224_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
s->len_chanlist = s->n_chan;
-
dev->write_subdev = s;
- s->do_cmd = &pci224_ao_cmd;
- s->do_cmdtest = &pci224_ao_cmdtest;
- s->cancel = &pci224_ao_cancel;
- s->munge = &pci224_ao_munge;
-
- /* Sort out channel range options. */
- if (thisboard->model == pci234_model) {
- /* PCI234 range options. */
- const struct comedi_lrange **range_table_list;
-
- s->range_table_list = range_table_list =
- kmalloc(sizeof(struct comedi_lrange *) * s->n_chan,
- GFP_KERNEL);
- if (!s->range_table_list)
- return -ENOMEM;
-
- if (options) {
- for (n = 2; n < 3 + s->n_chan; n++) {
- if (options[n] < 0 || options[n] > 1) {
- dev_warn(dev->class_dev,
- "warning! bad options[%u]=%d\n",
- n, options[n]);
- }
- }
- }
- for (n = 0; n < s->n_chan; n++) {
- if (n < COMEDI_NDEVCONFOPTS - 3 && options &&
- options[3 + n] == 1) {
- if (options[2] == 1)
- range_table_list[n] = &range_pci234_ext;
- else
- range_table_list[n] = &range_bipolar5;
-
- } else {
- if (options && options[2] == 1) {
- range_table_list[n] =
- &range_pci234_ext2;
- } else {
- range_table_list[n] = &range_bipolar10;
- }
- }
- }
- devpriv->hwrange = hwrange_pci234;
- } else {
- /* PCI224 range options. */
- if (options && options[2] == 1) {
- s->range_table = &range_pci224_external;
- devpriv->hwrange = hwrange_pci224_external;
- } else {
- if (options && options[2] != 0) {
- dev_warn(dev->class_dev,
- "warning! bad options[2]=%d\n",
- options[2]);
- }
- s->range_table = &range_pci224_internal;
- devpriv->hwrange = hwrange_pci224_internal;
- }
- }
+ s->do_cmd = pci224_ao_cmd;
+ s->do_cmdtest = pci224_ao_cmdtest;
+ s->cancel = pci224_ao_cancel;
+ s->munge = pci224_ao_munge;
- dev->board_name = thisboard->name;
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
if (irq) {
ret = request_irq(irq, pci224_interrupt, IRQF_SHARED,
@@ -1258,80 +1121,20 @@ static int pci224_attach_common(struct comedi_device *dev,
return 0;
}
-static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct pci224_private *devpriv;
- struct pci_dev *pci_dev;
-
- dev_info(dev->class_dev, "attach\n");
-
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
- pci_dev = pci224_find_pci_dev(dev, it);
- if (!pci_dev)
- return -EIO;
-
- return pci224_attach_common(dev, pci_dev, it->options);
-}
-
-static int
-pci224_auto_attach(struct comedi_device *dev, unsigned long context_unused)
-{
- struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
- struct pci224_private *devpriv;
-
- dev_info(dev->class_dev, "attach pci %s\n", pci_name(pci_dev));
-
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
- dev->board_ptr = pci224_find_pci_board(pci_dev);
- if (dev->board_ptr == NULL) {
- dev_err(dev->class_dev,
- "BUG! cannot determine board type!\n");
- return -EINVAL;
- }
- /*
- * Need to 'get' the PCI device to match the 'put' in pci224_detach().
- * TODO: Remove the pci_dev_get() and matching pci_dev_put() once
- * support for manual attachment of PCI devices via pci224_attach()
- * has been removed.
- */
- pci_dev_get(pci_dev);
- return pci224_attach_common(dev, pci_dev, NULL);
-}
-
static void pci224_detach(struct comedi_device *dev)
{
struct pci224_private *devpriv = dev->private;
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->subdevices) {
- struct comedi_subdevice *s;
-
- s = &dev->subdevices[0];
- /* AO subdevice */
- kfree(s->range_table_list);
- }
+ comedi_pci_detach(dev);
if (devpriv) {
- kfree(devpriv->ao_readback);
kfree(devpriv->ao_scan_vals);
kfree(devpriv->ao_scan_order);
}
- comedi_pci_disable(dev);
- if (pcidev)
- pci_dev_put(pcidev);
}
static struct comedi_driver amplc_pci224_driver = {
.driver_name = "amplc_pci224",
.module = THIS_MODULE,
- .attach = pci224_attach,
.detach = pci224_detach,
.auto_attach = pci224_auto_attach,
.board_name = &pci224_boards[0].name,
@@ -1347,8 +1150,8 @@ static int amplc_pci224_pci_probe(struct pci_dev *dev,
}
static const struct pci_device_id amplc_pci224_pci_table[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) },
+ { PCI_VDEVICE(AMPLICON, 0x0007), pci224_model },
+ { PCI_VDEVICE(AMPLICON, 0x0008), pci234_model },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, amplc_pci224_pci_table);
@@ -1362,5 +1165,5 @@ static struct pci_driver amplc_pci224_pci_driver = {
module_comedi_pci_driver(amplc_pci224_driver, amplc_pci224_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for Amplicon PCI224 and PCI234 AO boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index 684275d76e8c..01796cd28e5b 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -24,24 +24,19 @@
* Author: Allan Willcox <allanwillcox@ozemail.com.au>,
* Steve D Sharples <steve.sharples@nottingham.ac.uk>,
* Ian Abbott <abbotti@mev.co.uk>
- * Updated: Wed, 22 Oct 2008 12:34:49 +0100
- * Devices: [Amplicon] PCI230 (pci230 or amplc_pci230),
- * PCI230+ (pci230+ or amplc_pci230),
- * PCI260 (pci260 or amplc_pci230), PCI260+ (pci260+ or amplc_pci230)
+ * Updated: Mon, 01 Sep 2014 10:09:16 +0000
+ * Devices: [Amplicon] PCI230 (amplc_pci230), PCI230+, PCI260, PCI260+
* Status: works
*
* Configuration options:
- * [0] - PCI bus of device (optional).
- * [1] - PCI slot of device (optional).
- * If bus/slot is not specified, the first available PCI device
- * will be used.
+ * none
*
- * Configuring a "amplc_pci230" will match any supported card and it will
- * choose the best match, picking the "+" models if possible. Configuring
- * a "pci230" will match a PCI230 or PCI230+ card and it will be treated as
- * a PCI230. Configuring a "pci260" will match a PCI260 or PCI260+ card
- * and it will be treated as a PCI260. Configuring a "pci230+" will match
- * a PCI230+ card. Configuring a "pci260+" will match a PCI260+ card.
+ * Manual configuration of PCI cards is not supported; they are configured
+ * automatically.
+ *
+ * The PCI230+ and PCI260+ have the same PCI device IDs as the PCI230 and
+ * PCI260, but can be distinguished by the the size of the PCI regions. A
+ * card will be configured as a "+" model if detected as such.
*
* Subdevices:
*
@@ -201,7 +196,6 @@
*/
#define PCI_DEVICE_ID_PCI230 0x0000
#define PCI_DEVICE_ID_PCI260 0x0006
-#define PCI_DEVICE_ID_INVALID 0xffff
/*
* PCI230 i/o space 1 registers.
@@ -427,16 +421,15 @@
* (Potentially) shared resources and their owners
*/
enum {
- RES_Z2CT0, /* Z2-CT0 */
- RES_Z2CT1, /* Z2-CT1 */
- RES_Z2CT2, /* Z2-CT2 */
- NUM_RESOURCES /* Number of (potentially) shared resources. */
+ RES_Z2CT0 = (1U << 0), /* Z2-CT0 */
+ RES_Z2CT1 = (1U << 1), /* Z2-CT1 */
+ RES_Z2CT2 = (1U << 2) /* Z2-CT2 */
};
enum {
- OWNER_NONE, /* Not owned */
OWNER_AICMD, /* Owned by AI command */
- OWNER_AOCMD /* Owned by AO command */
+ OWNER_AOCMD, /* Owned by AO command */
+ NUM_OWNERS /* Number of owners */
};
/*
@@ -449,10 +442,6 @@ enum {
/* Current CPU. XXX should this be hard_smp_processor_id()? */
#define THISCPU smp_processor_id()
-/* State flags for atomic bit operations */
-#define AI_CMD_STARTED 0
-#define AO_CMD_STARTED 1
-
/*
* Board descriptions for the two boards supported.
*/
@@ -460,52 +449,39 @@ enum {
struct pci230_board {
const char *name;
unsigned short id;
- int ai_chans;
- int ai_bits;
- int ao_chans;
- int ao_bits;
- int have_dio;
- unsigned int min_hwver; /* Minimum hardware version supported. */
+ unsigned char ai_bits;
+ unsigned char ao_bits;
+ unsigned char min_hwver; /* Minimum hardware version supported. */
+ bool have_dio:1;
};
static const struct pci230_board pci230_boards[] = {
{
.name = "pci230+",
.id = PCI_DEVICE_ID_PCI230,
- .ai_chans = 16,
.ai_bits = 16,
- .ao_chans = 2,
.ao_bits = 12,
- .have_dio = 1,
+ .have_dio = true,
.min_hwver = 1,
},
{
.name = "pci260+",
.id = PCI_DEVICE_ID_PCI260,
- .ai_chans = 16,
.ai_bits = 16,
.min_hwver = 1,
},
{
.name = "pci230",
.id = PCI_DEVICE_ID_PCI230,
- .ai_chans = 16,
.ai_bits = 12,
- .ao_chans = 2,
.ao_bits = 12,
- .have_dio = 1,
+ .have_dio = true,
},
{
.name = "pci260",
.id = PCI_DEVICE_ID_PCI260,
- .ai_chans = 16,
.ai_bits = 12,
},
- {
- /* Wildcard matches any above */
- .name = "amplc_pci230",
- .id = PCI_DEVICE_ID_INVALID,
- },
};
struct pci230_private {
@@ -513,9 +489,7 @@ struct pci230_private {
spinlock_t res_spinlock; /* Shared resources spin lock */
spinlock_t ai_stop_spinlock; /* Spin lock for stopping AI command */
spinlock_t ao_stop_spinlock; /* Spin lock for stopping AO command */
- unsigned long state; /* State flags */
- unsigned long iobase1; /* PCI230's I/O space 1 */
- unsigned int ao_readback[2]; /* Used for AO readback */
+ unsigned long daqio; /* PCI230's DAQ I/O space */
unsigned int ai_scan_count; /* Number of AI scans remaining */
unsigned int ai_scan_pos; /* Current position within AI scan */
unsigned int ao_scan_count; /* Number of AO scans remaining. */
@@ -525,12 +499,13 @@ struct pci230_private {
unsigned short daccon; /* DACCON register value */
unsigned short adcfifothresh; /* ADC FIFO threshold (PCI230+/260+) */
unsigned short adcg; /* ADCG register value */
- unsigned char int_en; /* Interrupt enable bits */
- unsigned char ai_bipolar; /* Flag AI range is bipolar */
- unsigned char ao_bipolar; /* Flag AO range is bipolar */
- unsigned char ier; /* Copy of interrupt enable register */
- unsigned char intr_running; /* Flag set in interrupt routine */
- unsigned char res_owner[NUM_RESOURCES]; /* Shared resource owners */
+ unsigned char ier; /* Interrupt enable bits */
+ unsigned char res_owned[NUM_OWNERS]; /* Owned resources */
+ bool intr_running:1; /* Flag set in interrupt routine */
+ bool ai_bipolar:1; /* Flag AI range is bipolar */
+ bool ao_bipolar:1; /* Flag AO range is bipolar */
+ bool ai_cmd_started:1; /* Flag AI command started */
+ bool ao_cmd_started:1; /* Flag AO command started */
};
/* PCI230 clock source periods in ns */
@@ -558,9 +533,6 @@ static const struct comedi_lrange pci230_ai_range = {
/* PCI230 analogue gain bits for each input range. */
static const unsigned char pci230_ai_gain[7] = { 0, 1, 2, 3, 1, 2, 3 };
-/* PCI230 adccon bipolar flag for each analogue input range. */
-static const unsigned char pci230_ai_bipolar[7] = { 1, 1, 1, 1, 0, 0, 0 };
-
/* PCI230 analogue output range table */
static const struct comedi_lrange pci230_ao_range = {
2, {
@@ -569,170 +541,122 @@ static const struct comedi_lrange pci230_ao_range = {
}
};
-/* PCI230 daccon bipolar flag for each analogue output range. */
-static const unsigned char pci230_ao_bipolar[2] = { 0, 1 };
-
static unsigned short pci230_ai_read(struct comedi_device *dev)
{
- const struct pci230_board *thisboard = comedi_board(dev);
+ const struct pci230_board *thisboard = dev->board_ptr;
struct pci230_private *devpriv = dev->private;
unsigned short data;
/* Read sample. */
- data = inw(dev->iobase + PCI230_ADCDATA);
+ data = inw(devpriv->daqio + PCI230_ADCDATA);
/*
* PCI230 is 12 bit - stored in upper bits of 16 bit register
* (lower four bits reserved for expansion). PCI230+ is 16 bit AI.
- */
- data = data >> (16 - thisboard->ai_bits);
-
- /*
+ *
* If a bipolar range was specified, mangle it
* (twos complement->straight binary).
*/
if (devpriv->ai_bipolar)
- data ^= 1 << (thisboard->ai_bits - 1);
-
+ data ^= 0x8000;
+ data >>= (16 - thisboard->ai_bits);
return data;
}
-static inline unsigned short pci230_ao_mangle_datum(struct comedi_device *dev,
- unsigned short datum)
+static unsigned short pci230_ao_mangle_datum(struct comedi_device *dev,
+ unsigned short datum)
{
- const struct pci230_board *thisboard = comedi_board(dev);
+ const struct pci230_board *thisboard = dev->board_ptr;
struct pci230_private *devpriv = dev->private;
/*
- * If a bipolar range was specified, mangle it
- * (straight binary->twos complement).
- */
- if (devpriv->ao_bipolar)
- datum ^= 1 << (thisboard->ao_bits - 1);
-
- /*
* PCI230 is 12 bit - stored in upper bits of 16 bit register (lower
* four bits reserved for expansion). PCI230+ is also 12 bit AO.
*/
datum <<= (16 - thisboard->ao_bits);
+ /*
+ * If a bipolar range was specified, mangle it
+ * (straight binary->twos complement).
+ */
+ if (devpriv->ao_bipolar)
+ datum ^= 0x8000;
return datum;
}
-static inline void pci230_ao_write_nofifo(struct comedi_device *dev,
- unsigned short datum,
- unsigned int chan)
+static void pci230_ao_write_nofifo(struct comedi_device *dev,
+ unsigned short datum, unsigned int chan)
{
struct pci230_private *devpriv = dev->private;
- /* Store unmangled datum to be read back later. */
- devpriv->ao_readback[chan] = datum;
-
/* Write mangled datum to appropriate DACOUT register. */
outw(pci230_ao_mangle_datum(dev, datum),
- dev->iobase + (((chan) == 0) ? PCI230_DACOUT1 : PCI230_DACOUT2));
+ devpriv->daqio + ((chan == 0) ? PCI230_DACOUT1 : PCI230_DACOUT2));
}
-static inline void pci230_ao_write_fifo(struct comedi_device *dev,
- unsigned short datum, unsigned int chan)
+static void pci230_ao_write_fifo(struct comedi_device *dev,
+ unsigned short datum, unsigned int chan)
{
struct pci230_private *devpriv = dev->private;
- /* Store unmangled datum to be read back later. */
- devpriv->ao_readback[chan] = datum;
-
/* Write mangled datum to appropriate DACDATA register. */
outw(pci230_ao_mangle_datum(dev, datum),
- dev->iobase + PCI230P2_DACDATA);
+ devpriv->daqio + PCI230P2_DACDATA);
}
-static int get_resources(struct comedi_device *dev, unsigned int res_mask,
- unsigned char owner)
+static bool pci230_claim_shared(struct comedi_device *dev,
+ unsigned char res_mask, unsigned int owner)
{
struct pci230_private *devpriv = dev->private;
- int ok;
- unsigned int i;
- unsigned int b;
- unsigned int claimed;
+ unsigned int o;
unsigned long irqflags;
- ok = 1;
- claimed = 0;
spin_lock_irqsave(&devpriv->res_spinlock, irqflags);
- for (b = 1, i = 0; (i < NUM_RESOURCES) && res_mask; b <<= 1, i++) {
- if (res_mask & b) {
- res_mask &= ~b;
- if (devpriv->res_owner[i] == OWNER_NONE) {
- devpriv->res_owner[i] = owner;
- claimed |= b;
- } else if (devpriv->res_owner[i] != owner) {
- for (b = 1, i = 0; claimed; b <<= 1, i++) {
- if (claimed & b) {
- devpriv->res_owner[i] =
- OWNER_NONE;
- claimed &= ~b;
- }
- }
- ok = 0;
- break;
- }
+ for (o = 0; o < NUM_OWNERS; o++) {
+ if (o == owner)
+ continue;
+ if (devpriv->res_owned[o] & res_mask) {
+ spin_unlock_irqrestore(&devpriv->res_spinlock,
+ irqflags);
+ return false;
}
}
+ devpriv->res_owned[owner] |= res_mask;
spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags);
- return ok;
-}
-
-static inline int get_one_resource(struct comedi_device *dev,
- unsigned int resource, unsigned char owner)
-{
- return get_resources(dev, (1U << resource), owner);
+ return true;
}
-static void put_resources(struct comedi_device *dev, unsigned int res_mask,
- unsigned char owner)
+static void pci230_release_shared(struct comedi_device *dev,
+ unsigned char res_mask, unsigned int owner)
{
struct pci230_private *devpriv = dev->private;
- unsigned int i;
- unsigned int b;
unsigned long irqflags;
spin_lock_irqsave(&devpriv->res_spinlock, irqflags);
- for (b = 1, i = 0; (i < NUM_RESOURCES) && res_mask; b <<= 1, i++) {
- if (res_mask & b) {
- res_mask &= ~b;
- if (devpriv->res_owner[i] == owner)
- devpriv->res_owner[i] = OWNER_NONE;
- }
- }
+ devpriv->res_owned[owner] &= ~res_mask;
spin_unlock_irqrestore(&devpriv->res_spinlock, irqflags);
}
-static inline void put_one_resource(struct comedi_device *dev,
- unsigned int resource, unsigned char owner)
+static void pci230_release_all_resources(struct comedi_device *dev,
+ unsigned int owner)
{
- put_resources(dev, (1U << resource), owner);
+ pci230_release_shared(dev, (unsigned char)~0, owner);
}
-static inline void put_all_resources(struct comedi_device *dev,
- unsigned char owner)
-{
- put_resources(dev, (1U << NUM_RESOURCES) - 1, owner);
-}
-
-static unsigned int divide_ns(uint64_t ns, unsigned int timebase,
- unsigned int flags)
+static unsigned int pci230_divide_ns(uint64_t ns, unsigned int timebase,
+ unsigned int flags)
{
uint64_t div;
unsigned int rem;
div = ns;
rem = do_div(div, timebase);
- switch (flags & TRIG_ROUND_MASK) {
+ switch (flags & CMDF_ROUND_MASK) {
default:
- case TRIG_ROUND_NEAREST:
+ case CMDF_ROUND_NEAREST:
div += (rem + (timebase / 2)) / timebase;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
div += (rem + timebase - 1) / timebase;
break;
}
@@ -749,8 +673,8 @@ static unsigned int pci230_choose_clk_count(uint64_t ns, unsigned int *count,
unsigned int clk_src, cnt;
for (clk_src = CLK_10MHZ;; clk_src++) {
- cnt = divide_ns(ns, pci230_timebase[clk_src], flags);
- if ((cnt <= 65536) || (clk_src == CLK_1KHZ))
+ cnt = pci230_divide_ns(ns, pci230_timebase[clk_src], flags);
+ if (cnt <= 65536 || clk_src == CLK_1KHZ)
break;
}
*count = cnt;
@@ -770,29 +694,25 @@ static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct,
unsigned int mode, uint64_t ns,
unsigned int flags)
{
- struct pci230_private *devpriv = dev->private;
unsigned int clk_src;
unsigned int count;
/* Set mode. */
- i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, mode);
+ i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, ct, mode);
/* Determine clock source and count. */
clk_src = pci230_choose_clk_count(ns, &count, flags);
/* Program clock source. */
- outb(CLK_CONFIG(ct, clk_src), devpriv->iobase1 + PCI230_ZCLK_SCE);
+ outb(CLK_CONFIG(ct, clk_src), dev->iobase + PCI230_ZCLK_SCE);
/* Set initial count. */
if (count >= 65536)
count = 0;
- i8254_write(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, count);
+ i8254_write(dev->iobase + PCI230_Z2_CT_BASE, 0, ct, count);
}
static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct)
{
- struct pci230_private *devpriv = dev->private;
-
- i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct,
- I8254_MODE1);
+ i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, ct, I8254_MODE1);
/* Counter ct, 8254 mode 1, initial count not written. */
}
@@ -801,17 +721,18 @@ static int pci230_ai_eoc(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned long context)
{
+ struct pci230_private *devpriv = dev->private;
unsigned int status;
- status = inw(dev->iobase + PCI230_ADCCON);
+ status = inw(devpriv->daqio + 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)
+static int pci230_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
{
struct pci230_private *devpriv = dev->private;
unsigned int n;
@@ -842,8 +763,8 @@ static int pci230_ai_rinsn(struct comedi_device *dev,
*/
adccon = PCI230_ADC_TRIG_Z2CT2 | PCI230_ADC_FIFO_EN;
/* Set Z2-CT2 output low to avoid any false triggers. */
- i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0);
- devpriv->ai_bipolar = pci230_ai_bipolar[range];
+ i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0);
+ devpriv->ai_bipolar = comedi_range_is_bipolar(s, range);
if (aref == AREF_DIFF) {
/* Differential. */
gainshift = chan * 2;
@@ -874,19 +795,18 @@ static int pci230_ai_rinsn(struct comedi_device *dev,
else
adccon |= PCI230_ADC_IR_UNI;
-
/*
* Enable only this channel in the scan list - otherwise by default
* we'll get one sample from each channel.
*/
- outw(adcen, dev->iobase + PCI230_ADCEN);
+ outw(adcen, devpriv->daqio + PCI230_ADCEN);
/* Set gain for channel. */
- outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
+ outw(devpriv->adcg, devpriv->daqio + PCI230_ADCG);
/* Specify uni/bip, se/diff, conversion source, and reset FIFO. */
devpriv->adccon = adccon;
- outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON);
+ outw(adccon | PCI230_ADC_FIFO_RESET, devpriv->daqio + PCI230_ADCCON);
/* Convert n samples */
for (n = 0; n < insn->n; n++) {
@@ -894,10 +814,10 @@ static int pci230_ai_rinsn(struct comedi_device *dev,
* Trigger conversion by toggling Z2-CT2 output
* (finish with output high).
*/
- i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
- I8254_MODE0);
- i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
- I8254_MODE1);
+ i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0,
+ 2, I8254_MODE0);
+ i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0,
+ 2, I8254_MODE1);
/* wait for conversion to end */
ret = comedi_timeout(dev, s, insn, pci230_ai_eoc, 0);
@@ -912,57 +832,31 @@ static int pci230_ai_rinsn(struct comedi_device *dev,
return n;
}
-/*
- * COMEDI_SUBD_AO instructions;
- */
-static int pci230_ao_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
+static int pci230_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct pci230_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int val = s->readback[chan];
int i;
- int chan, range;
-
- /* Unpack channel and range. */
- chan = CR_CHAN(insn->chanspec);
- range = CR_RANGE(insn->chanspec);
/*
* Set range - see analogue output range table; 0 => unipolar 10V,
* 1 => bipolar +/-10V range scale
*/
- devpriv->ao_bipolar = pci230_ao_bipolar[range];
- outw(range, dev->iobase + PCI230_DACCON);
+ devpriv->ao_bipolar = comedi_range_is_bipolar(s, range);
+ outw(range, devpriv->daqio + PCI230_DACCON);
- /*
- * Writing a list of values to an AO channel is probably not
- * very useful, but that's how the interface is defined.
- */
for (i = 0; i < insn->n; i++) {
- /* Write value to DAC and store it. */
- pci230_ao_write_nofifo(dev, data[i], chan);
+ val = data[i];
+ pci230_ao_write_nofifo(dev, val, chan);
}
+ s->readback[chan] = val;
- /* return the number of samples read/written */
- return i;
-}
-
-/*
- * AO subdevices should have a read insn as well as a write insn.
- * Usually this means copying a value stored in devpriv.
- */
-static int pci230_ao_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
-{
- struct pci230_private *devpriv = dev->private;
- int i;
- int chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return i;
+ return insn->n;
}
static int pci230_ao_check_chanlist(struct comedi_device *dev,
@@ -1000,7 +894,7 @@ static int pci230_ao_check_chanlist(struct comedi_device *dev,
static int pci230_ao_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
- const struct pci230_board *thisboard = comedi_board(dev);
+ const struct pci230_board *thisboard = dev->board_ptr;
struct pci230_private *devpriv = dev->private;
int err = 0;
unsigned int tmp;
@@ -1010,7 +904,7 @@ static int pci230_ao_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
tmp = TRIG_TIMER | TRIG_INT;
- if ((thisboard->min_hwver > 0) && (devpriv->hwver >= 2)) {
+ if (thisboard->min_hwver > 0 && devpriv->hwver >= 2) {
/*
* For PCI230+ hardware version 2 onwards, allow external
* trigger from EXTTRIG/EXTCONVCLK input (PCI230+ pin 25).
@@ -1078,11 +972,11 @@ static int pci230_ao_cmdtest(struct comedi_device *dev,
* The only flags allowed are CR_EDGE and CR_INVERT.
* The CR_EDGE flag is ignored.
*/
- if (cmd->scan_begin_arg &
- (CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT))) {
- cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
- CR_FLAGS_MASK &
- ~(CR_EDGE | CR_INVERT));
+ if (cmd->scan_begin_arg & CR_FLAGS_MASK &
+ ~(CR_EDGE | CR_INVERT)) {
+ cmd->scan_begin_arg =
+ COMBINE(cmd->scan_begin_arg, 0,
+ CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT));
err |= -EINVAL;
}
break;
@@ -1093,7 +987,9 @@ static int pci230_ao_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_NONE)
+ 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)
@@ -1127,11 +1023,12 @@ static void pci230_ao_stop(struct comedi_device *dev,
struct pci230_private *devpriv = dev->private;
unsigned long irqflags;
unsigned char intsrc;
- int started;
+ bool started;
struct comedi_cmd *cmd;
spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags);
- started = test_and_clear_bit(AO_CMD_STARTED, &devpriv->state);
+ started = devpriv->ao_cmd_started;
+ devpriv->ao_cmd_started = false;
spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags);
if (!started)
return;
@@ -1153,15 +1050,12 @@ static void pci230_ao_stop(struct comedi_device *dev,
* unless we are called from the interrupt routine.
*/
spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
- devpriv->int_en &= ~intsrc;
+ devpriv->ier &= ~intsrc;
while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
}
- if (devpriv->ier != devpriv->int_en) {
- devpriv->ier = devpriv->int_en;
- outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
- }
+ outb(devpriv->ier, dev->iobase + PCI230_INT_SCE);
spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
if (devpriv->hwver >= 2) {
/*
@@ -1171,10 +1065,10 @@ static void pci230_ao_stop(struct comedi_device *dev,
devpriv->daccon &= PCI230_DAC_OR_MASK;
outw(devpriv->daccon | PCI230P2_DAC_FIFO_RESET |
PCI230P2_DAC_FIFO_UNDERRUN_CLEAR,
- dev->iobase + PCI230_DACCON);
+ devpriv->daqio + PCI230_DACCON);
}
/* Release resources. */
- put_all_resources(dev, OWNER_AOCMD);
+ pci230_release_all_resources(dev, OWNER_AOCMD);
}
static void pci230_handle_ao_nofifo(struct comedi_device *dev,
@@ -1189,6 +1083,8 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev,
if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0)
return;
for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+
/* Read sample from Comedi's circular buffer. */
ret = comedi_buf_get(s, &data);
if (ret == 0) {
@@ -1197,8 +1093,8 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev,
dev_err(dev->class_dev, "AO buffer underrun\n");
return;
}
- /* Write value to DAC. */
- pci230_ao_write_nofifo(dev, data, CR_CHAN(cmd->chanlist[i]));
+ pci230_ao_write_nofifo(dev, data, chan);
+ s->readback[chan] = data;
}
async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
if (cmd->stop_src == TRIG_COUNT) {
@@ -1211,10 +1107,12 @@ static void pci230_handle_ao_nofifo(struct comedi_device *dev,
}
}
-/* Loads DAC FIFO (if using it) from buffer. */
-/* Returns 0 if AO finished due to completion or error, 1 if still going. */
-static int pci230_handle_ao_fifo(struct comedi_device *dev,
- struct comedi_subdevice *s)
+/*
+ * Loads DAC FIFO (if using it) from buffer.
+ * Returns false if AO finished due to completion or error, true if still going.
+ */
+static bool pci230_handle_ao_fifo(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct pci230_private *devpriv = dev->private;
struct comedi_async *async = s->async;
@@ -1224,10 +1122,10 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev,
unsigned short dacstat;
unsigned int i, n;
unsigned int events = 0;
- int running;
+ bool running;
/* Get DAC FIFO status. */
- dacstat = inw(dev->iobase + PCI230_DACCON);
+ dacstat = inw(devpriv->daqio + PCI230_DACCON);
/* Determine number of scans available in buffer. */
num_scans = comedi_buf_read_n_available(s) / cfc_bytes_per_scan(s);
if (cmd->stop_src == TRIG_COUNT) {
@@ -1250,8 +1148,8 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev,
* (otherwise there will be loads of "DAC FIFO not half full"
* interrupts).
*/
- if ((num_scans == 0) &&
- ((dacstat & PCI230P2_DAC_FIFO_HALF) == 0)) {
+ if (num_scans == 0 &&
+ (dacstat & PCI230P2_DAC_FIFO_HALF) == 0) {
dev_err(dev->class_dev, "AO buffer underrun\n");
events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
}
@@ -1274,11 +1172,12 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev,
/* Process scans. */
for (n = 0; n < num_scans; n++) {
for (i = 0; i < cmd->chanlist_len; i++) {
+ unsigned int chan = CR_CHAN(cmd->chanlist[i]);
unsigned short datum;
comedi_buf_get(s, &datum);
- pci230_ao_write_fifo(dev, datum,
- CR_CHAN(cmd->chanlist[i]));
+ pci230_ao_write_fifo(dev, datum, chan);
+ s->readback[chan] = datum;
}
}
events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK;
@@ -1295,11 +1194,11 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev,
~PCI230P2_DAC_INT_FIFO_MASK) |
PCI230P2_DAC_INT_FIFO_EMPTY;
outw(devpriv->daccon,
- dev->iobase + PCI230_DACCON);
+ devpriv->daqio + PCI230_DACCON);
}
}
/* Check if FIFO underrun occurred while writing to FIFO. */
- dacstat = inw(dev->iobase + PCI230_DACCON);
+ dacstat = inw(devpriv->daqio + PCI230_DACCON);
if (dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) {
dev_err(dev->class_dev, "AO FIFO underrun\n");
events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
@@ -1308,9 +1207,9 @@ static int pci230_handle_ao_fifo(struct comedi_device *dev,
if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
/* Stopping AO due to completion or error. */
pci230_ao_stop(dev, s);
- running = 0;
+ running = false;
} else {
- running = 1;
+ running = true;
}
async->events |= events;
return running;
@@ -1327,28 +1226,25 @@ static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev,
return -EINVAL;
spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags);
- if (test_bit(AO_CMD_STARTED, &devpriv->state)) {
- /* Perform scan. */
- if (devpriv->hwver < 2) {
- /* Not using DAC FIFO. */
- spin_unlock_irqrestore(&devpriv->ao_stop_spinlock,
- irqflags);
- pci230_handle_ao_nofifo(dev, s);
- comedi_event(dev, s);
- } else {
- /* Using DAC FIFO. */
- /* Read DACSWTRIG register to trigger conversion. */
- inw(dev->iobase + PCI230P2_DACSWTRIG);
- spin_unlock_irqrestore(&devpriv->ao_stop_spinlock,
- irqflags);
- }
- /* Delay. Should driver be responsible for this? */
- /* XXX TODO: See if DAC busy bit can be used. */
- udelay(8);
+ if (!devpriv->ao_cmd_started) {
+ spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags);
+ return 1;
+ }
+ /* Perform scan. */
+ if (devpriv->hwver < 2) {
+ /* Not using DAC FIFO. */
+ spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags);
+ pci230_handle_ao_nofifo(dev, s);
+ comedi_event(dev, s);
} else {
+ /* Using DAC FIFO. */
+ /* Read DACSWTRIG register to trigger conversion. */
+ inw(devpriv->daqio + PCI230P2_DACSWTRIG);
spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags);
}
-
+ /* Delay. Should driver be responsible for this? */
+ /* XXX TODO: See if DAC busy bit can be used. */
+ udelay(8);
return 1;
}
@@ -1360,84 +1256,71 @@ static void pci230_ao_start(struct comedi_device *dev,
struct comedi_cmd *cmd = &async->cmd;
unsigned long irqflags;
- set_bit(AO_CMD_STARTED, &devpriv->state);
- if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0) {
- /* An empty acquisition! */
- async->events |= COMEDI_CB_EOA;
- pci230_ao_stop(dev, s);
+ devpriv->ao_cmd_started = true;
+
+ if (devpriv->hwver >= 2) {
+ /* Using DAC FIFO. */
+ unsigned short scantrig;
+ bool run;
+
+ /* Preload FIFO data. */
+ run = pci230_handle_ao_fifo(dev, s);
comedi_event(dev, s);
- } else {
- if (devpriv->hwver >= 2) {
- /* Using DAC FIFO. */
- unsigned short scantrig;
- int run;
-
- /* Preload FIFO data. */
- run = pci230_handle_ao_fifo(dev, s);
- comedi_event(dev, s);
- if (!run) {
- /* Stopped. */
- return;
- }
- /* Set scan trigger source. */
- switch (cmd->scan_begin_src) {
- case TRIG_TIMER:
- scantrig = PCI230P2_DAC_TRIG_Z2CT1;
- break;
- case TRIG_EXT:
- /* Trigger on EXTTRIG/EXTCONVCLK pin. */
- if ((cmd->scan_begin_arg & CR_INVERT) == 0) {
- /* +ve edge */
- scantrig = PCI230P2_DAC_TRIG_EXTP;
- } else {
- /* -ve edge */
- scantrig = PCI230P2_DAC_TRIG_EXTN;
- }
- break;
- case TRIG_INT:
- scantrig = PCI230P2_DAC_TRIG_SW;
- break;
- default:
- /* Shouldn't get here. */
- scantrig = PCI230P2_DAC_TRIG_NONE;
- break;
- }
- devpriv->daccon =
- (devpriv->daccon & ~PCI230P2_DAC_TRIG_MASK) |
- scantrig;
- outw(devpriv->daccon, dev->iobase + PCI230_DACCON);
+ if (!run) {
+ /* Stopped. */
+ return;
}
+ /* Set scan trigger source. */
switch (cmd->scan_begin_src) {
case TRIG_TIMER:
- if (devpriv->hwver < 2) {
- /* Not using DAC FIFO. */
- /* Enable CT1 timer interrupt. */
- spin_lock_irqsave(&devpriv->isr_spinlock,
- irqflags);
- devpriv->int_en |= PCI230_INT_ZCLK_CT1;
- devpriv->ier |= PCI230_INT_ZCLK_CT1;
- outb(devpriv->ier,
- devpriv->iobase1 + PCI230_INT_SCE);
- spin_unlock_irqrestore(&devpriv->isr_spinlock,
- irqflags);
+ scantrig = PCI230P2_DAC_TRIG_Z2CT1;
+ break;
+ case TRIG_EXT:
+ /* Trigger on EXTTRIG/EXTCONVCLK pin. */
+ if ((cmd->scan_begin_arg & CR_INVERT) == 0) {
+ /* +ve edge */
+ scantrig = PCI230P2_DAC_TRIG_EXTP;
+ } else {
+ /* -ve edge */
+ scantrig = PCI230P2_DAC_TRIG_EXTN;
}
- /* Set CT1 gate high to start counting. */
- outb(GAT_CONFIG(1, GAT_VCC),
- devpriv->iobase1 + PCI230_ZGAT_SCE);
break;
case TRIG_INT:
- async->inttrig = pci230_ao_inttrig_scan_begin;
+ scantrig = PCI230P2_DAC_TRIG_SW;
+ break;
+ default:
+ /* Shouldn't get here. */
+ scantrig = PCI230P2_DAC_TRIG_NONE;
break;
}
- if (devpriv->hwver >= 2) {
- /* Using DAC FIFO. Enable DAC FIFO interrupt. */
+ devpriv->daccon =
+ (devpriv->daccon & ~PCI230P2_DAC_TRIG_MASK) | scantrig;
+ outw(devpriv->daccon, devpriv->daqio + PCI230_DACCON);
+ }
+ switch (cmd->scan_begin_src) {
+ case TRIG_TIMER:
+ if (devpriv->hwver < 2) {
+ /* Not using DAC FIFO. */
+ /* Enable CT1 timer interrupt. */
spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
- devpriv->int_en |= PCI230P2_INT_DAC;
- devpriv->ier |= PCI230P2_INT_DAC;
- outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
+ devpriv->ier |= PCI230_INT_ZCLK_CT1;
+ outb(devpriv->ier, dev->iobase + PCI230_INT_SCE);
spin_unlock_irqrestore(&devpriv->isr_spinlock,
irqflags);
}
+ /* Set CT1 gate high to start counting. */
+ outb(GAT_CONFIG(1, GAT_VCC), dev->iobase + PCI230_ZGAT_SCE);
+ break;
+ case TRIG_INT:
+ async->inttrig = pci230_ao_inttrig_scan_begin;
+ break;
+ }
+ if (devpriv->hwver >= 2) {
+ /* Using DAC FIFO. Enable DAC FIFO interrupt. */
+ spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
+ devpriv->ier |= PCI230P2_INT_DAC;
+ outb(devpriv->ier, dev->iobase + PCI230_INT_SCE);
+ spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
}
}
@@ -1467,22 +1350,18 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (cmd->scan_begin_src == TRIG_TIMER) {
/* Claim Z2-CT1. */
- if (!get_one_resource(dev, RES_Z2CT1, OWNER_AOCMD))
+ if (!pci230_claim_shared(dev, RES_Z2CT1, OWNER_AOCMD))
return -EBUSY;
}
- /* Get number of scans required. */
- if (cmd->stop_src == TRIG_COUNT)
- devpriv->ao_scan_count = cmd->stop_arg;
- else /* TRIG_NONE, user calls cancel */
- devpriv->ao_scan_count = 0;
+ devpriv->ao_scan_count = cmd->stop_arg;
/*
* Set range - see analogue output range table; 0 => unipolar 10V,
* 1 => bipolar +/-10V range scale
*/
range = CR_RANGE(cmd->chanlist[0]);
- devpriv->ao_bipolar = pci230_ao_bipolar[range];
+ devpriv->ao_bipolar = comedi_range_is_bipolar(s, range);
daccon = devpriv->ao_bipolar ? PCI230_DAC_OR_BIP : PCI230_DAC_OR_UNI;
/* Use DAC FIFO for hardware version 2 onwards. */
if (devpriv->hwver >= 2) {
@@ -1494,7 +1373,7 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
dacen |= 1 << CR_CHAN(cmd->chanlist[i]);
/* Set channel scan list. */
- outw(dacen, dev->iobase + PCI230P2_DACEN);
+ outw(dacen, devpriv->daqio + PCI230P2_DACEN);
/*
* Enable DAC FIFO.
* Set DAC scan source to 'none'.
@@ -1509,7 +1388,7 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
/* Set DACCON. */
- outw(daccon, dev->iobase + PCI230_DACCON);
+ outw(daccon, devpriv->daqio + PCI230_DACCON);
/* Preserve most of DACCON apart from write-only, transient bits. */
devpriv->daccon = daccon & ~(PCI230P2_DAC_FIFO_RESET |
PCI230P2_DAC_FIFO_UNDERRUN_CLEAR);
@@ -1520,8 +1399,7 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* cmd->scan_begin_arg is sampling period in ns.
* Gate it off for now.
*/
- outb(GAT_CONFIG(1, GAT_GND),
- devpriv->iobase1 + PCI230_ZGAT_SCE);
+ outb(GAT_CONFIG(1, GAT_GND), dev->iobase + PCI230_ZGAT_SCE);
pci230_ct_setup_ns_mode(dev, 1, I8254_MODE3,
cmd->scan_begin_arg,
cmd->flags);
@@ -1550,8 +1428,8 @@ static int pci230_ai_check_scan_period(struct comedi_cmd *cmd)
chanlist_len = 1;
min_scan_period = chanlist_len * cmd->convert_arg;
- if ((min_scan_period < chanlist_len) ||
- (min_scan_period < cmd->convert_arg)) {
+ if (min_scan_period < chanlist_len ||
+ min_scan_period < cmd->convert_arg) {
/* Arithmetic overflow. */
min_scan_period = UINT_MAX;
err++;
@@ -1573,7 +1451,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev,
unsigned int prev_chan = 0;
unsigned int prev_range = 0;
unsigned int prev_aref = 0;
- unsigned int prev_polarity = 0;
+ bool prev_bipolar = false;
unsigned int subseq_len = 0;
int i;
@@ -1582,7 +1460,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev,
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];
+ bool bipolar = comedi_range_is_bipolar(s, range);
if (aref == AREF_DIFF && chan >= max_diff_chan) {
dev_dbg(dev->class_dev,
@@ -1614,7 +1492,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev,
return -EINVAL;
}
- if (polarity != prev_polarity) {
+ if (bipolar != prev_bipolar) {
dev_dbg(dev->class_dev,
"%s: channel sequence ranges must be all bipolar or all unipolar\n",
__func__);
@@ -1632,7 +1510,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev,
prev_chan = chan;
prev_range = range;
prev_aref = aref;
- prev_polarity = polarity;
+ prev_bipolar = bipolar;
}
if (subseq_len == 0)
@@ -1670,7 +1548,7 @@ static int pci230_ai_check_chanlist(struct comedi_device *dev,
static int pci230_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
- const struct pci230_board *thisboard = comedi_board(dev);
+ const struct pci230_board *thisboard = dev->board_ptr;
struct pci230_private *devpriv = dev->private;
int err = 0;
unsigned int tmp;
@@ -1680,7 +1558,7 @@ static int pci230_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
tmp = TRIG_FOLLOW | TRIG_TIMER | TRIG_INT;
- if ((thisboard->have_dio) || (thisboard->min_hwver > 0)) {
+ if (thisboard->have_dio || thisboard->min_hwver > 0) {
/*
* Unfortunately, we cannot trigger a scan off an external
* source on the PCI260 board, since it uses the PPIC0 (DIO)
@@ -1711,8 +1589,8 @@ static int pci230_ai_cmdtest(struct comedi_device *dev,
* If scan_begin_src is not TRIG_FOLLOW, then a monostable will be
* set up to generate a fixed number of timed conversion pulses.
*/
- if ((cmd->scan_begin_src != TRIG_FOLLOW) &&
- (cmd->convert_src != TRIG_TIMER))
+ if (cmd->scan_begin_src != TRIG_FOLLOW &&
+ cmd->convert_src != TRIG_TIMER)
err |= -EINVAL;
if (err)
@@ -1739,7 +1617,7 @@ static int pci230_ai_cmdtest(struct comedi_device *dev,
* PCI230 or PCI260. Max speed depends whether
* single-ended or pseudo-differential.
*/
- if (cmd->chanlist && (cmd->chanlist_len > 0)) {
+ if (cmd->chanlist && cmd->chanlist_len > 0) {
/* Peek analogue reference of first channel. */
if (CR_AREF(cmd->chanlist[0]) == AREF_DIFF)
max_speed_ai = MAX_SPEED_AI_DIFF;
@@ -1779,13 +1657,12 @@ static int pci230_ai_cmdtest(struct comedi_device *dev,
* The only flags allowed are CR_INVERT and CR_EDGE.
* CR_EDGE is required.
*/
- if ((cmd->convert_arg &
- (CR_FLAGS_MASK & ~CR_INVERT)) != CR_EDGE) {
+ if ((cmd->convert_arg & CR_FLAGS_MASK & ~CR_INVERT) !=
+ CR_EDGE) {
/* Set CR_EDGE, preserve CR_INVERT. */
- cmd->convert_arg = COMBINE(cmd->start_arg,
- (CR_EDGE | 0),
- CR_FLAGS_MASK &
- ~CR_INVERT);
+ cmd->convert_arg =
+ COMBINE(cmd->start_arg, CR_EDGE | 0,
+ CR_FLAGS_MASK & ~CR_INVERT);
err |= -EINVAL;
}
} else {
@@ -1802,7 +1679,9 @@ static int pci230_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_NONE)
+ 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 (cmd->scan_begin_src == TRIG_EXT) {
@@ -1850,7 +1729,7 @@ static int pci230_ai_cmdtest(struct comedi_device *dev,
if (!pci230_ai_check_scan_period(cmd)) {
/* Was below minimum required. Round up. */
pci230_ns_to_single_timer(&cmd->scan_begin_arg,
- TRIG_ROUND_UP);
+ CMDF_ROUND_UP);
pci230_ai_check_scan_period(cmd);
}
if (tmp != cmd->scan_begin_arg)
@@ -1880,37 +1759,30 @@ static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev,
unsigned short triglev;
unsigned short adccon;
- if (cmd->flags & TRIG_WAKE_EOS) {
- /* Wake at end of scan. */
+ if (cmd->flags & CMDF_WAKE_EOS)
wake = scanlen - devpriv->ai_scan_pos;
- } else {
- 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) -
- devpriv->ai_scan_pos;
- }
- }
+ else 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 - devpriv->ai_scan_pos;
if (wake >= PCI230_ADC_FIFOLEVEL_HALFFULL) {
triglev = PCI230_ADC_INT_FIFO_HALF;
- } else {
- if ((wake > 1) && (devpriv->hwver > 0)) {
- /* PCI230+/260+ programmable FIFO interrupt level. */
- if (devpriv->adcfifothresh != wake) {
- devpriv->adcfifothresh = wake;
- outw(wake, dev->iobase + PCI230P_ADCFFTH);
- }
- triglev = PCI230P_ADC_INT_FIFO_THRESH;
- } else {
- triglev = PCI230_ADC_INT_FIFO_NEMPTY;
+ } else if (wake > 1 && devpriv->hwver > 0) {
+ /* PCI230+/260+ programmable FIFO interrupt level. */
+ if (devpriv->adcfifothresh != wake) {
+ devpriv->adcfifothresh = wake;
+ outw(wake, devpriv->daqio + PCI230P_ADCFFTH);
}
+ triglev = PCI230P_ADC_INT_FIFO_THRESH;
+ } else {
+ triglev = PCI230_ADC_INT_FIFO_NEMPTY;
}
adccon = (devpriv->adccon & ~PCI230_ADC_INT_FIFO_MASK) | triglev;
if (adccon != devpriv->adccon) {
devpriv->adccon = adccon;
- outw(adccon, dev->iobase + PCI230_ADCCON);
+ outw(adccon, devpriv->daqio + PCI230_ADCCON);
}
}
@@ -1920,43 +1792,39 @@ static int pci230_ai_inttrig_convert(struct comedi_device *dev,
{
struct pci230_private *devpriv = dev->private;
unsigned long irqflags;
+ unsigned int delayus;
if (trig_num)
return -EINVAL;
spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
- if (test_bit(AI_CMD_STARTED, &devpriv->state)) {
- unsigned int delayus;
-
- /*
- * Trigger conversion by toggling Z2-CT2 output.
- * Finish with output high.
- */
- i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
- I8254_MODE0);
- i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2,
- I8254_MODE1);
- /*
- * Delay. Should driver be responsible for this? An
- * alternative would be to wait until conversion is complete,
- * but we can't tell when it's complete because the ADC busy
- * bit has a different meaning when FIFO enabled (and when
- * FIFO not enabled, it only works for software triggers).
- */
- if (((devpriv->adccon & PCI230_ADC_IM_MASK) ==
- PCI230_ADC_IM_DIF) && (devpriv->hwver == 0)) {
- /* PCI230/260 in differential mode */
- delayus = 8;
- } else {
- /* single-ended or PCI230+/260+ */
- delayus = 4;
- }
+ if (!devpriv->ai_cmd_started) {
spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
- udelay(delayus);
+ return 1;
+ }
+ /*
+ * Trigger conversion by toggling Z2-CT2 output.
+ * Finish with output high.
+ */
+ i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0);
+ i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1);
+ /*
+ * Delay. Should driver be responsible for this? An
+ * alternative would be to wait until conversion is complete,
+ * but we can't tell when it's complete because the ADC busy
+ * bit has a different meaning when FIFO enabled (and when
+ * FIFO not enabled, it only works for software triggers).
+ */
+ if ((devpriv->adccon & PCI230_ADC_IM_MASK) == PCI230_ADC_IM_DIF &&
+ devpriv->hwver == 0) {
+ /* PCI230/260 in differential mode */
+ delayus = 8;
} else {
- spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
+ /* single-ended or PCI230+/260+ */
+ delayus = 4;
}
-
+ spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
+ udelay(delayus);
return 1;
}
@@ -1972,12 +1840,12 @@ static int pci230_ai_inttrig_scan_begin(struct comedi_device *dev,
return -EINVAL;
spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
- if (test_bit(AI_CMD_STARTED, &devpriv->state)) {
+ if (devpriv->ai_cmd_started) {
/* Trigger scan by waggling CT0 gate source. */
zgat = GAT_CONFIG(0, GAT_GND);
- outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
+ outb(zgat, dev->iobase + PCI230_ZGAT_SCE);
zgat = GAT_CONFIG(0, GAT_VCC);
- outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
+ outb(zgat, dev->iobase + PCI230_ZGAT_SCE);
}
spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
@@ -1990,10 +1858,11 @@ static void pci230_ai_stop(struct comedi_device *dev,
struct pci230_private *devpriv = dev->private;
unsigned long irqflags;
struct comedi_cmd *cmd;
- int started;
+ bool started;
spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
- started = test_and_clear_bit(AI_CMD_STARTED, &devpriv->state);
+ started = devpriv->ai_cmd_started;
+ devpriv->ai_cmd_started = false;
spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags);
if (!started)
return;
@@ -2011,15 +1880,12 @@ static void pci230_ai_stop(struct comedi_device *dev,
* Disable ADC interrupt and wait for interrupt routine to finish
* running unless we are called from the interrupt routine.
*/
- devpriv->int_en &= ~PCI230_INT_ADC;
+ devpriv->ier &= ~PCI230_INT_ADC;
while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
}
- if (devpriv->ier != devpriv->int_en) {
- devpriv->ier = devpriv->int_en;
- outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
- }
+ outb(devpriv->ier, dev->iobase + PCI230_INT_SCE);
spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
/*
* Reset FIFO, disable FIFO and set start conversion source to none.
@@ -2029,9 +1895,9 @@ static void pci230_ai_stop(struct comedi_device *dev,
(devpriv->adccon & (PCI230_ADC_IR_MASK | PCI230_ADC_IM_MASK)) |
PCI230_ADC_TRIG_NONE;
outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
- dev->iobase + PCI230_ADCCON);
+ devpriv->daqio + PCI230_ADCCON);
/* Release resources. */
- put_all_resources(dev, OWNER_AICMD);
+ pci230_release_all_resources(dev, OWNER_AICMD);
}
static void pci230_ai_start(struct comedi_device *dev,
@@ -2043,145 +1909,132 @@ static void pci230_ai_start(struct comedi_device *dev,
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
- set_bit(AI_CMD_STARTED, &devpriv->state);
- if (cmd->stop_src == TRIG_COUNT && devpriv->ai_scan_count == 0) {
- /* An empty acquisition! */
- async->events |= COMEDI_CB_EOA;
- pci230_ai_stop(dev, s);
- comedi_event(dev, s);
- } else {
- /* Enable ADC FIFO trigger level interrupt. */
- spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
- devpriv->int_en |= PCI230_INT_ADC;
- devpriv->ier |= PCI230_INT_ADC;
- outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
- spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
+ devpriv->ai_cmd_started = true;
- /*
- * Update conversion trigger source which is currently set
- * to CT2 output, which is currently stuck high.
- */
- switch (cmd->convert_src) {
- default:
- conv = PCI230_ADC_TRIG_NONE;
- break;
- case TRIG_TIMER:
- /* Using CT2 output. */
- conv = PCI230_ADC_TRIG_Z2CT2;
- break;
- case TRIG_EXT:
- if (cmd->convert_arg & CR_EDGE) {
- if ((cmd->convert_arg & CR_INVERT) == 0) {
- /* Trigger on +ve edge. */
- conv = PCI230_ADC_TRIG_EXTP;
- } else {
- /* Trigger on -ve edge. */
- conv = PCI230_ADC_TRIG_EXTN;
- }
+ /* Enable ADC FIFO trigger level interrupt. */
+ spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
+ devpriv->ier |= PCI230_INT_ADC;
+ outb(devpriv->ier, dev->iobase + PCI230_INT_SCE);
+ spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
+
+ /*
+ * Update conversion trigger source which is currently set
+ * to CT2 output, which is currently stuck high.
+ */
+ switch (cmd->convert_src) {
+ default:
+ conv = PCI230_ADC_TRIG_NONE;
+ break;
+ case TRIG_TIMER:
+ /* Using CT2 output. */
+ conv = PCI230_ADC_TRIG_Z2CT2;
+ break;
+ case TRIG_EXT:
+ if (cmd->convert_arg & CR_EDGE) {
+ if ((cmd->convert_arg & CR_INVERT) == 0) {
+ /* Trigger on +ve edge. */
+ conv = PCI230_ADC_TRIG_EXTP;
} else {
- /* Backwards compatibility. */
- if (cmd->convert_arg) {
- /* Trigger on +ve edge. */
- conv = PCI230_ADC_TRIG_EXTP;
- } else {
- /* Trigger on -ve edge. */
- conv = PCI230_ADC_TRIG_EXTN;
- }
+ /* Trigger on -ve edge. */
+ conv = PCI230_ADC_TRIG_EXTN;
+ }
+ } else {
+ /* Backwards compatibility. */
+ if (cmd->convert_arg) {
+ /* Trigger on +ve edge. */
+ conv = PCI230_ADC_TRIG_EXTP;
+ } else {
+ /* Trigger on -ve edge. */
+ conv = PCI230_ADC_TRIG_EXTN;
}
- break;
- case TRIG_INT:
- /*
- * Use CT2 output for software trigger due to problems
- * in differential mode on PCI230/260.
- */
- conv = PCI230_ADC_TRIG_Z2CT2;
- break;
}
- devpriv->adccon =
- (devpriv->adccon & ~PCI230_ADC_TRIG_MASK) | conv;
- outw(devpriv->adccon, dev->iobase + PCI230_ADCCON);
- if (cmd->convert_src == TRIG_INT)
- async->inttrig = pci230_ai_inttrig_convert;
-
+ break;
+ case TRIG_INT:
/*
- * Update FIFO interrupt trigger level, which is currently
- * set to "full".
+ * Use CT2 output for software trigger due to problems
+ * in differential mode on PCI230/260.
*/
- pci230_ai_update_fifo_trigger_level(dev, s);
- if (cmd->convert_src == TRIG_TIMER) {
- /* Update timer gates. */
- unsigned char zgat;
+ conv = PCI230_ADC_TRIG_Z2CT2;
+ break;
+ }
+ devpriv->adccon = (devpriv->adccon & ~PCI230_ADC_TRIG_MASK) | conv;
+ outw(devpriv->adccon, devpriv->daqio + PCI230_ADCCON);
+ if (cmd->convert_src == TRIG_INT)
+ async->inttrig = pci230_ai_inttrig_convert;
- if (cmd->scan_begin_src != TRIG_FOLLOW) {
+ /*
+ * Update FIFO interrupt trigger level, which is currently
+ * set to "full".
+ */
+ pci230_ai_update_fifo_trigger_level(dev, s);
+ if (cmd->convert_src == TRIG_TIMER) {
+ /* Update timer gates. */
+ unsigned char zgat;
+
+ if (cmd->scan_begin_src != TRIG_FOLLOW) {
+ /*
+ * Conversion timer CT2 needs to be gated by
+ * inverted output of monostable CT2.
+ */
+ zgat = GAT_CONFIG(2, GAT_NOUTNM2);
+ } else {
+ /*
+ * Conversion timer CT2 needs to be gated on
+ * continuously.
+ */
+ zgat = GAT_CONFIG(2, GAT_VCC);
+ }
+ outb(zgat, dev->iobase + PCI230_ZGAT_SCE);
+ if (cmd->scan_begin_src != TRIG_FOLLOW) {
+ /* Set monostable CT0 trigger source. */
+ switch (cmd->scan_begin_src) {
+ default:
+ zgat = GAT_CONFIG(0, GAT_VCC);
+ break;
+ case TRIG_EXT:
/*
- * Conversion timer CT2 needs to be gated by
- * inverted output of monostable CT2.
+ * For CT0 on PCI230, the external trigger
+ * (gate) signal comes from PPC0, which is
+ * channel 16 of the DIO subdevice. The
+ * application needs to configure this as an
+ * input in order to use it as an external scan
+ * trigger.
*/
- zgat = GAT_CONFIG(2, GAT_NOUTNM2);
- } else {
+ zgat = GAT_CONFIG(0, GAT_EXT);
+ break;
+ case TRIG_TIMER:
/*
- * Conversion timer CT2 needs to be gated on
- * continuously.
+ * Monostable CT0 triggered by rising edge on
+ * inverted output of CT1 (falling edge on CT1).
*/
- zgat = GAT_CONFIG(2, GAT_VCC);
+ zgat = GAT_CONFIG(0, GAT_NOUTNM2);
+ break;
+ case TRIG_INT:
+ /*
+ * Monostable CT0 is triggered by inttrig
+ * function waggling the CT0 gate source.
+ */
+ zgat = GAT_CONFIG(0, GAT_VCC);
+ break;
}
- outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
- if (cmd->scan_begin_src != TRIG_FOLLOW) {
- /* Set monostable CT0 trigger source. */
- switch (cmd->scan_begin_src) {
- default:
- zgat = GAT_CONFIG(0, GAT_VCC);
- break;
- case TRIG_EXT:
- /*
- * For CT0 on PCI230, the external
- * trigger (gate) signal comes from
- * PPC0, which is channel 16 of the DIO
- * subdevice. The application needs to
- * configure this as an input in order
- * to use it as an external scan
- * trigger.
- */
- zgat = GAT_CONFIG(0, GAT_EXT);
- break;
- case TRIG_TIMER:
- /*
- * Monostable CT0 triggered by rising
- * edge on inverted output of CT1
- * (falling edge on CT1).
- */
- zgat = GAT_CONFIG(0, GAT_NOUTNM2);
- break;
- case TRIG_INT:
- /*
- * Monostable CT0 is triggered by
- * inttrig function waggling the CT0
- * gate source.
- */
- zgat = GAT_CONFIG(0, GAT_VCC);
- break;
- }
- outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
- switch (cmd->scan_begin_src) {
- case TRIG_TIMER:
- /*
- * Scan period timer CT1 needs to be
- * gated on to start counting.
- */
- zgat = GAT_CONFIG(1, GAT_VCC);
- outb(zgat, devpriv->iobase1 +
- PCI230_ZGAT_SCE);
- break;
- case TRIG_INT:
- async->inttrig =
- pci230_ai_inttrig_scan_begin;
- break;
- }
+ outb(zgat, dev->iobase + PCI230_ZGAT_SCE);
+ switch (cmd->scan_begin_src) {
+ case TRIG_TIMER:
+ /*
+ * Scan period timer CT1 needs to be
+ * gated on to start counting.
+ */
+ zgat = GAT_CONFIG(1, GAT_VCC);
+ outb(zgat, dev->iobase + PCI230_ZGAT_SCE);
+ break;
+ case TRIG_INT:
+ async->inttrig = pci230_ai_inttrig_scan_begin;
+ break;
}
- } else if (cmd->convert_src != TRIG_INT) {
- /* No longer need Z2-CT2. */
- put_one_resource(dev, RES_Z2CT2, OWNER_AICMD);
}
+ } else if (cmd->convert_src != TRIG_INT) {
+ /* No longer need Z2-CT2. */
+ pci230_release_shared(dev, RES_Z2CT2, OWNER_AICMD);
}
}
@@ -2218,12 +2071,11 @@ static void pci230_handle_ai(struct comedi_device *dev,
todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
} else if (devpriv->ai_scan_count == 0) {
todo = 0;
- } else if ((devpriv->ai_scan_count > PCI230_ADC_FIFOLEVEL_HALFFULL) ||
- (scanlen > PCI230_ADC_FIFOLEVEL_HALFFULL)) {
+ } else if (devpriv->ai_scan_count > PCI230_ADC_FIFOLEVEL_HALFFULL ||
+ scanlen > PCI230_ADC_FIFOLEVEL_HALFFULL) {
todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
} else {
- todo = (devpriv->ai_scan_count * scanlen) -
- devpriv->ai_scan_pos;
+ todo = devpriv->ai_scan_count * scanlen - devpriv->ai_scan_pos;
if (todo > PCI230_ADC_FIFOLEVEL_HALFFULL)
todo = PCI230_ADC_FIFOLEVEL_HALFFULL;
}
@@ -2233,7 +2085,7 @@ static void pci230_handle_ai(struct comedi_device *dev,
for (i = 0; i < todo; i++) {
if (fifoamount == 0) {
/* Read FIFO state. */
- status_fifo = inw(dev->iobase + PCI230_ADCCON);
+ status_fifo = inw(devpriv->daqio + PCI230_ADCCON);
if (status_fifo & PCI230_ADC_FIFO_FULL_LATCHED) {
/*
* Report error otherwise FIFO overruns will go
@@ -2248,19 +2100,15 @@ static void pci230_handle_ai(struct comedi_device *dev,
} else if (status_fifo & PCI230_ADC_FIFO_HALF) {
/* FIFO half full. */
fifoamount = PCI230_ADC_FIFOLEVEL_HALFFULL;
+ } else if (devpriv->hwver > 0) {
+ /* Read PCI230+/260+ ADC FIFO level. */
+ fifoamount = inw(devpriv->daqio +
+ PCI230P_ADCFFLEV);
+ if (fifoamount == 0)
+ break; /* Shouldn't happen. */
} else {
/* FIFO not empty. */
- if (devpriv->hwver > 0) {
- /* Read PCI230+/260+ ADC FIFO level. */
- fifoamount =
- inw(dev->iobase + PCI230P_ADCFFLEV);
- if (fifoamount == 0) {
- /* Shouldn't happen. */
- break;
- }
- } else {
- fifoamount = 1;
- }
+ fifoamount = 1;
}
}
/* Read sample and store in Comedi's circular buffer. */
@@ -2316,25 +2164,20 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* Need Z2-CT2 to supply a conversion trigger source at a high
* logic level, even if not doing timed conversions.
*/
- res_mask |= (1U << RES_Z2CT2);
+ res_mask |= RES_Z2CT2;
if (cmd->scan_begin_src != TRIG_FOLLOW) {
/* Using Z2-CT0 monostable to gate Z2-CT2 conversion timer */
- res_mask |= (1U << RES_Z2CT0);
+ res_mask |= RES_Z2CT0;
if (cmd->scan_begin_src == TRIG_TIMER) {
/* Using Z2-CT1 for scan frequency */
- res_mask |= (1U << RES_Z2CT1);
+ res_mask |= RES_Z2CT1;
}
}
/* Claim resources. */
- if (!get_resources(dev, res_mask, OWNER_AICMD))
+ if (!pci230_claim_shared(dev, res_mask, OWNER_AICMD))
return -EBUSY;
-
- /* Get number of scans required. */
- if (cmd->stop_src == TRIG_COUNT)
- devpriv->ai_scan_count = cmd->stop_arg;
- else /* TRIG_NONE, user calls cancel */
- devpriv->ai_scan_count = 0;
+ devpriv->ai_scan_count = cmd->stop_arg;
devpriv->ai_scan_pos = 0; /* Position within scan. */
/*
@@ -2369,7 +2212,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
range = CR_RANGE(cmd->chanlist[0]);
- devpriv->ai_bipolar = pci230_ai_bipolar[range];
+ devpriv->ai_bipolar = comedi_range_is_bipolar(s, range);
if (devpriv->ai_bipolar)
adccon |= PCI230_ADC_IR_BIP;
else
@@ -2396,7 +2239,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
adcen |= 1 << gainshift;
}
} else {
- gainshift = (chan & ~1);
+ gainshift = chan & ~1;
adcen |= 1 << chan;
}
devpriv->adcg = (devpriv->adcg & ~(3 << gainshift)) |
@@ -2404,16 +2247,16 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
/* Set channel scan list. */
- outw(adcen, dev->iobase + PCI230_ADCEN);
+ outw(adcen, devpriv->daqio + PCI230_ADCEN);
/* Set channel gains. */
- outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
+ outw(devpriv->adcg, devpriv->daqio + PCI230_ADCG);
/*
* Set counter/timer 2 output high for use as the initial start
* conversion source.
*/
- i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1);
+ i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1);
/*
* Temporarily use CT2 output as conversion trigger source and
@@ -2429,7 +2272,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* PCI230/260, but that will be dealt with later.
*/
devpriv->adccon = adccon;
- outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON);
+ outw(adccon | PCI230_ADC_FIFO_RESET, devpriv->daqio + PCI230_ADCCON);
/*
* Delay -
@@ -2443,7 +2286,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
usleep_range(25, 100);
/* Reset FIFO again. */
- outw(adccon | PCI230_ADC_FIFO_RESET, dev->iobase + PCI230_ADCCON);
+ outw(adccon | PCI230_ADC_FIFO_RESET, devpriv->daqio + PCI230_ADCCON);
if (cmd->convert_src == TRIG_TIMER) {
/*
@@ -2452,7 +2295,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* connector: PCI230 pin 21, PCI260 pin 18.
*/
zgat = GAT_CONFIG(2, GAT_GND);
- outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
+ outb(zgat, dev->iobase + PCI230_ZGAT_SCE);
/* Set counter/timer 2 to the specified conversion period. */
pci230_ct_setup_ns_mode(dev, 2, I8254_MODE3, cmd->convert_arg,
cmd->flags);
@@ -2470,11 +2313,11 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* source will be changed later.
*/
zgat = GAT_CONFIG(0, GAT_VCC);
- outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
+ outb(zgat, dev->iobase + PCI230_ZGAT_SCE);
pci230_ct_setup_ns_mode(dev, 0, I8254_MODE1,
((uint64_t)cmd->convert_arg *
cmd->scan_end_arg),
- TRIG_ROUND_UP);
+ CMDF_ROUND_UP);
if (cmd->scan_begin_src == TRIG_TIMER) {
/*
* Monostable on CT0 will be triggered by
@@ -2483,7 +2326,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* Set up CT1 but gate it off for now.
*/
zgat = GAT_CONFIG(1, GAT_GND);
- outb(zgat, devpriv->iobase1 + PCI230_ZGAT_SCE);
+ outb(zgat, dev->iobase + PCI230_ZGAT_SCE);
pci230_ct_setup_ns_mode(dev, 1, I8254_MODE3,
cmd->scan_begin_arg,
cmd->flags);
@@ -2509,29 +2352,28 @@ static int pci230_ai_cancel(struct comedi_device *dev,
/* Interrupt handler */
static irqreturn_t pci230_interrupt(int irq, void *d)
{
- unsigned char status_int, valid_status_int;
+ unsigned char status_int, valid_status_int, temp_ier;
struct comedi_device *dev = (struct comedi_device *)d;
struct pci230_private *devpriv = dev->private;
struct comedi_subdevice *s;
unsigned long irqflags;
/* Read interrupt status/enable register. */
- status_int = inb(devpriv->iobase1 + PCI230_INT_STAT);
+ status_int = inb(dev->iobase + PCI230_INT_STAT);
if (status_int == PCI230_INT_DISABLE)
return IRQ_NONE;
-
spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
- valid_status_int = devpriv->int_en & status_int;
+ valid_status_int = devpriv->ier & status_int;
/*
* Disable triggered interrupts.
* (Only those interrupts that need re-enabling, are, later in the
* handler).
*/
- devpriv->ier = devpriv->int_en & ~status_int;
- outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
- devpriv->intr_running = 1;
+ temp_ier = devpriv->ier & ~status_int;
+ outb(temp_ier, dev->iobase + PCI230_INT_SCE);
+ devpriv->intr_running = true;
devpriv->intr_cpuid = THISCPU;
spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
@@ -2563,11 +2405,9 @@ static irqreturn_t pci230_interrupt(int irq, void *d)
/* Reenable interrupts. */
spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
- if (devpriv->ier != devpriv->int_en) {
- devpriv->ier = devpriv->int_en;
- outb(devpriv->ier, devpriv->iobase1 + PCI230_INT_SCE);
- }
- devpriv->intr_running = 0;
+ if (devpriv->ier != temp_ier)
+ outb(devpriv->ier, dev->iobase + PCI230_INT_SCE);
+ devpriv->intr_running = false;
spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
return IRQ_HANDLED;
@@ -2603,49 +2443,17 @@ static const struct pci230_board *pci230_find_pci_board(struct pci_dev *pci_dev)
return NULL;
}
-/* Look for PCI device matching requested board name, bus and slot. */
-static struct pci_dev *pci230_find_pci_dev(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- const struct pci230_board *thisboard = comedi_board(dev);
- struct pci_dev *pci_dev = NULL;
- int bus = it->options[0];
- int slot = it->options[1];
-
- for_each_pci_dev(pci_dev) {
- /* Check vendor ID (same for all supported PCI boards). */
- if (pci_dev->vendor != PCI_VENDOR_ID_AMPLICON)
- continue;
- /* If bus/slot specified, check them. */
- if ((bus || slot) &&
- (bus != pci_dev->bus->number ||
- slot != PCI_SLOT(pci_dev->devfn)))
- continue;
- if (thisboard->id == PCI_DEVICE_ID_INVALID) {
- /* Wildcard board matches any supported PCI board. */
- const struct pci230_board *foundboard;
-
- foundboard = pci230_find_pci_board(pci_dev);
- if (foundboard == NULL)
- continue;
- /* Replace wildcard board_ptr. */
- dev->board_ptr = foundboard;
- } else {
- /* Need to match a specific board. */
- if (!pci230_match_pci_board(thisboard, pci_dev))
- continue;
- }
- return pci_dev;
- }
- dev_err(dev->class_dev,
- "No supported board found! (req. bus %d, slot %d)\n",
- bus, slot);
- return NULL;
-}
-
-static int pci230_alloc_private(struct comedi_device *dev)
+static int pci230_auto_attach(struct comedi_device *dev,
+ unsigned long context_unused)
{
+ struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
+ const struct pci230_board *thisboard;
struct pci230_private *devpriv;
+ struct comedi_subdevice *s;
+ int rc;
+
+ dev_info(dev->class_dev, "amplc_pci230: attach pci %s\n",
+ pci_name(pci_dev));
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
@@ -2655,22 +2463,14 @@ static int pci230_alloc_private(struct comedi_device *dev)
spin_lock_init(&devpriv->res_spinlock);
spin_lock_init(&devpriv->ai_stop_spinlock);
spin_lock_init(&devpriv->ao_stop_spinlock);
- return 0;
-}
-
-/* Common part of attach and auto_attach. */
-static int pci230_attach_common(struct comedi_device *dev,
- struct pci_dev *pci_dev)
-{
- const struct pci230_board *thisboard = comedi_board(dev);
- struct pci230_private *devpriv = dev->private;
- struct comedi_subdevice *s;
- unsigned long iobase1, iobase2;
- /* PCI230's I/O spaces 1 and 2 respectively. */
- int rc;
-
- comedi_set_hw_dev(dev, &pci_dev->dev);
+ dev->board_ptr = pci230_find_pci_board(pci_dev);
+ if (dev->board_ptr == NULL) {
+ dev_err(dev->class_dev,
+ "amplc_pci230: BUG! cannot determine board type!\n");
+ return -EINVAL;
+ }
+ thisboard = dev->board_ptr;
dev->board_name = thisboard->name;
rc = comedi_pci_enable(dev);
@@ -2681,15 +2481,14 @@ static int pci230_attach_common(struct comedi_device *dev,
* Read base addresses of the PCI230's two I/O regions from PCI
* configuration register.
*/
- iobase1 = pci_resource_start(pci_dev, 2);
- iobase2 = pci_resource_start(pci_dev, 3);
+ dev->iobase = pci_resource_start(pci_dev, 2);
+ devpriv->daqio = pci_resource_start(pci_dev, 3);
dev_dbg(dev->class_dev,
"%s I/O region 1 0x%04lx I/O region 2 0x%04lx\n",
- dev->board_name, iobase1, iobase2);
- devpriv->iobase1 = iobase1;
- dev->iobase = iobase2;
+ dev->board_name, dev->iobase, devpriv->daqio);
/* Read bits of DACCON register - only the output range. */
- devpriv->daccon = inw(dev->iobase + PCI230_DACCON) & PCI230_DAC_OR_MASK;
+ devpriv->daccon = inw(devpriv->daqio + PCI230_DACCON) &
+ PCI230_DAC_OR_MASK;
/*
* Read hardware version register and set extended function register
* if they exist.
@@ -2697,7 +2496,7 @@ static int pci230_attach_common(struct comedi_device *dev,
if (pci_resource_len(pci_dev, 3) >= 32) {
unsigned short extfunc = 0;
- devpriv->hwver = inw(dev->iobase + PCI230P_HWVER);
+ devpriv->hwver = inw(devpriv->daqio + PCI230P_HWVER);
if (devpriv->hwver < thisboard->min_hwver) {
dev_err(dev->class_dev,
"%s - bad hardware version - got %u, need %u\n",
@@ -2716,13 +2515,12 @@ static int pci230_attach_common(struct comedi_device *dev,
*/
extfunc |= PCI230P_EXTFUNC_GAT_EXTTRIG;
}
- if ((thisboard->ao_chans > 0) &&
- (devpriv->hwver >= 2)) {
+ if (thisboard->ao_bits && devpriv->hwver >= 2) {
/* Enable DAC FIFO functionality. */
extfunc |= PCI230P2_EXTFUNC_DACFIFO;
}
}
- outw(extfunc, dev->iobase + PCI230P_EXTFUNC);
+ outw(extfunc, devpriv->daqio + PCI230P_EXTFUNC);
if (extfunc & PCI230P2_EXTFUNC_DACFIFO) {
/*
* Temporarily enable DAC FIFO, reset it and disable
@@ -2730,23 +2528,23 @@ static int pci230_attach_common(struct comedi_device *dev,
*/
outw(devpriv->daccon | PCI230P2_DAC_FIFO_EN |
PCI230P2_DAC_FIFO_RESET,
- dev->iobase + PCI230_DACCON);
+ devpriv->daqio + PCI230_DACCON);
/* Clear DAC FIFO channel enable register. */
- outw(0, dev->iobase + PCI230P2_DACEN);
+ outw(0, devpriv->daqio + PCI230P2_DACEN);
/* Disable DAC FIFO. */
- outw(devpriv->daccon, dev->iobase + PCI230_DACCON);
+ outw(devpriv->daccon, devpriv->daqio + PCI230_DACCON);
}
}
/* Disable board's interrupts. */
- outb(0, devpriv->iobase1 + PCI230_INT_SCE);
+ outb(0, dev->iobase + PCI230_INT_SCE);
/* Set ADC to a reasonable state. */
devpriv->adcg = 0;
devpriv->adccon = PCI230_ADC_TRIG_NONE | PCI230_ADC_IM_SE |
PCI230_ADC_IR_BIP;
- outw(1 << 0, dev->iobase + PCI230_ADCEN);
- outw(devpriv->adcg, dev->iobase + PCI230_ADCG);
+ outw(1 << 0, devpriv->daqio + PCI230_ADCEN);
+ outw(devpriv->adcg, devpriv->daqio + PCI230_ADCG);
outw(devpriv->adccon | PCI230_ADC_FIFO_RESET,
- dev->iobase + PCI230_ADCCON);
+ devpriv->daqio + PCI230_ADCCON);
if (pci_dev->irq) {
rc = request_irq(pci_dev->irq, pci230_interrupt, IRQF_SHARED,
@@ -2763,10 +2561,10 @@ static int pci230_attach_common(struct comedi_device *dev,
/* analog input subdevice */
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND;
- s->n_chan = thisboard->ai_chans;
+ s->n_chan = 16;
s->maxdata = (1 << thisboard->ai_bits) - 1;
s->range_table = &pci230_ai_range;
- s->insn_read = pci230_ai_rinsn;
+ s->insn_read = pci230_ai_insn_read;
s->len_chanlist = 256; /* but there are restrictions. */
if (dev->irq) {
dev->read_subdev = s;
@@ -2778,15 +2576,15 @@ static int pci230_attach_common(struct comedi_device *dev,
s = &dev->subdevices[1];
/* analog output subdevice */
- if (thisboard->ao_chans > 0) {
+ if (thisboard->ao_bits) {
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
- s->n_chan = thisboard->ao_chans;
+ s->n_chan = 2;
s->maxdata = (1 << thisboard->ao_bits) - 1;
s->range_table = &pci230_ao_range;
- s->insn_write = pci230_ao_winsn;
- s->insn_read = pci230_ao_rinsn;
- s->len_chanlist = thisboard->ao_chans;
+ s->insn_write = pci230_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+ s->len_chanlist = 2;
if (dev->irq) {
dev->write_subdev = s;
s->subdev_flags |= SDF_CMD_WRITE;
@@ -2794,6 +2592,10 @@ static int pci230_attach_common(struct comedi_device *dev,
s->do_cmdtest = pci230_ao_cmdtest;
s->cancel = pci230_ao_cancel;
}
+
+ rc = comedi_alloc_subdev_readback(s);
+ if (rc)
+ return rc;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -2801,8 +2603,7 @@ static int pci230_attach_common(struct comedi_device *dev,
s = &dev->subdevices[2];
/* digital i/o subdevice */
if (thisboard->have_dio) {
- rc = subdev_8255_init(dev, s, NULL,
- devpriv->iobase1 + PCI230_PPI_X_BASE);
+ rc = subdev_8255_init(dev, s, NULL, PCI230_PPI_X_BASE);
if (rc)
return rc;
} else {
@@ -2812,74 +2613,11 @@ static int pci230_attach_common(struct comedi_device *dev,
return 0;
}
-static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- const struct pci230_board *thisboard = comedi_board(dev);
- struct pci_dev *pci_dev;
- int rc;
-
- dev_info(dev->class_dev, "amplc_pci230: attach %s %d,%d\n",
- thisboard->name, it->options[0], it->options[1]);
-
- rc = pci230_alloc_private(dev);
- if (rc)
- return rc;
-
- pci_dev = pci230_find_pci_dev(dev, it);
- if (!pci_dev)
- return -EIO;
- return pci230_attach_common(dev, pci_dev);
-}
-
-static int pci230_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
-{
- struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
- int rc;
-
- dev_info(dev->class_dev, "amplc_pci230: attach pci %s\n",
- pci_name(pci_dev));
-
- rc = pci230_alloc_private(dev);
- if (rc)
- return rc;
-
- dev->board_ptr = pci230_find_pci_board(pci_dev);
- if (dev->board_ptr == NULL) {
- dev_err(dev->class_dev,
- "amplc_pci230: BUG! cannot determine board type!\n");
- return -EINVAL;
- }
- /*
- * Need to 'get' the PCI device to match the 'put' in pci230_detach().
- * TODO: Remove the pci_dev_get() and matching pci_dev_put() once
- * support for manual attachment of PCI devices via pci230_attach()
- * has been removed.
- */
- pci_dev_get(pci_dev);
- return pci230_attach_common(dev, pci_dev);
-}
-
-static void pci230_detach(struct comedi_device *dev)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
- if (dev->irq)
- free_irq(dev->irq, dev);
- comedi_pci_disable(dev);
- if (pcidev)
- pci_dev_put(pcidev);
-}
-
static struct comedi_driver amplc_pci230_driver = {
.driver_name = "amplc_pci230",
.module = THIS_MODULE,
- .attach = pci230_attach,
.auto_attach = pci230_auto_attach,
- .detach = pci230_detach,
- .board_name = &pci230_boards[0].name,
- .offset = sizeof(pci230_boards[0]),
- .num_names = ARRAY_SIZE(pci230_boards),
+ .detach = comedi_pci_detach,
};
static int amplc_pci230_pci_probe(struct pci_dev *dev,
@@ -2905,5 +2643,5 @@ static struct pci_driver amplc_pci230_pci_driver = {
module_comedi_pci_driver(amplc_pci230_driver, amplc_pci230_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for Amplicon PCI230(+) and PCI260(+)");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pci236.c b/drivers/staging/comedi/drivers/amplc_pci236.c
index 436aebaf7621..ad1e93dd13a0 100644
--- a/drivers/staging/comedi/drivers/amplc_pci236.c
+++ b/drivers/staging/comedi/drivers/amplc_pci236.c
@@ -119,18 +119,11 @@ static int pci236_auto_attach(struct comedi_device *dev,
IRQF_SHARED);
}
-static void pci236_detach(struct comedi_device *dev)
-{
- if (dev->irq)
- free_irq(dev->irq, dev);
- comedi_pci_disable(dev);
-}
-
static struct comedi_driver amplc_pci236_driver = {
.driver_name = "amplc_pci236",
.module = THIS_MODULE,
.auto_attach = pci236_auto_attach,
- .detach = pci236_detach,
+ .detach = comedi_pci_detach,
};
static const struct pci_device_id pci236_pci_table[] = {
diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c
index 748a6b108f32..2259bee98d48 100644
--- a/drivers/staging/comedi/drivers/amplc_pci263.c
+++ b/drivers/staging/comedi/drivers/amplc_pci263.c
@@ -86,7 +86,7 @@ static struct comedi_driver amplc_pci263_driver = {
.driver_name = "amplc_pci263",
.module = THIS_MODULE,
.auto_attach = pci263_auto_attach,
- .detach = comedi_pci_disable,
+ .detach = comedi_pci_detach,
};
static const struct pci_device_id pci263_pci_table[] = {
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index 853733e28845..f88880aea6da 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -79,7 +79,6 @@ static const struct das16cs_board das16cs_boards[] = {
};
struct das16cs_private {
- unsigned int ao_readback[2];
unsigned short status1;
unsigned short status2;
};
@@ -153,20 +152,20 @@ static int das16cs_ai_rinsn(struct comedi_device *dev,
return i;
}
-static int das16cs_ao_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int das16cs_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct das16cs_private *devpriv = dev->private;
- int i;
- int chan = CR_CHAN(insn->chanspec);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = s->readback[chan];
unsigned short status1;
- unsigned short d;
int bit;
+ int i;
for (i = 0; i < insn->n; i++) {
- devpriv->ao_readback[chan] = data[i];
- d = data[i];
+ val = data[i];
outw(devpriv->status1, dev->iobase + DAS16CS_MISC1);
udelay(1);
@@ -181,7 +180,7 @@ static int das16cs_ao_winsn(struct comedi_device *dev,
udelay(1);
for (bit = 15; bit >= 0; bit--) {
- int b = (d >> bit) & 0x1;
+ int b = (val >> bit) & 0x1;
b <<= 1;
outw(status1 | b | 0x0000, dev->iobase + DAS16CS_MISC1);
@@ -195,22 +194,9 @@ static int das16cs_ao_winsn(struct comedi_device *dev,
*/
outw(status1 | 0x9, dev->iobase + DAS16CS_MISC1);
}
+ s->readback[chan] = val;
- return i;
-}
-
-static int das16cs_ao_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct das16cs_private *devpriv = dev->private;
- int i;
- int chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return i;
+ return insn->n;
}
static int das16cs_dio_insn_bits(struct comedi_device *dev,
@@ -318,8 +304,12 @@ static int das16cs_auto_attach(struct comedi_device *dev,
s->n_chan = board->n_ao_chans;
s->maxdata = 0xffff;
s->range_table = &range_bipolar10;
- s->insn_write = &das16cs_ao_winsn;
- s->insn_read = &das16cs_ao_rinsn;
+ s->insn_write = &das16cs_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index 4a7bd4e5dd72..1ec363b7505c 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -342,7 +342,6 @@ struct cb_pcidas_private {
unsigned long s5933_config;
unsigned long control_status;
unsigned long adc_fifo;
- unsigned long pacer_counter_dio;
unsigned long ao_registers;
/* divisors of master clock for analog input pacing */
unsigned int divisor1;
@@ -361,8 +360,6 @@ struct cb_pcidas_private {
unsigned int ao_divisor2;
/* number of analog output samples remaining */
unsigned int ao_count;
- /* cached values for readback */
- unsigned short ao_value[2];
unsigned int caldac_value[NUM_CHANNELS_8800];
unsigned int trimpot_value[NUM_CHANNELS_8402];
unsigned int dac08_value;
@@ -485,7 +482,7 @@ static int cb_pcidas_ao_nofifo_winsn(struct comedi_device *dev,
spin_unlock_irqrestore(&dev->spinlock, flags);
/* remember value for readback */
- devpriv->ao_value[chan] = data[0];
+ s->readback[chan] = data[0];
/* send data */
outw(data[0], devpriv->ao_registers + DAC_DATA_REG(chan));
@@ -516,7 +513,7 @@ static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev,
spin_unlock_irqrestore(&dev->spinlock, flags);
/* remember value for readback */
- devpriv->ao_value[chan] = data[0];
+ s->readback[chan] = data[0];
/* send data */
outw(data[0], devpriv->ao_registers + DACDATA);
@@ -524,18 +521,6 @@ static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev,
return insn->n;
}
-static int cb_pcidas_ao_readback_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct cb_pcidas_private *devpriv = dev->private;
-
- data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)];
-
- return 1;
-}
-
static int wait_for_nvram_ready(unsigned long s5933_base_addr)
{
static const int timeout = 1000;
@@ -758,7 +743,7 @@ static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel,
static int cb_pcidas_trimpot_write(struct comedi_device *dev,
unsigned int channel, unsigned int value)
{
- const struct cb_pcidas_board *thisboard = comedi_board(dev);
+ const struct cb_pcidas_board *thisboard = dev->board_ptr;
struct cb_pcidas_private *devpriv = dev->private;
if (devpriv->trimpot_value[channel] == value)
@@ -832,7 +817,7 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct cb_pcidas_board *thisboard = comedi_board(dev);
+ const struct cb_pcidas_board *thisboard = dev->board_ptr;
struct cb_pcidas_private *devpriv = dev->private;
int err = 0;
unsigned int arg;
@@ -901,7 +886,9 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_NONE)
+ 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)
@@ -942,7 +929,7 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
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;
+ unsigned long timer_base = dev->iobase + ADC8254;
i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
@@ -954,7 +941,7 @@ static void cb_pcidas_ai_load_counters(struct comedi_device *dev)
static int cb_pcidas_ai_cmd(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- const struct cb_pcidas_board *thisboard = comedi_board(dev);
+ const struct cb_pcidas_board *thisboard = dev->board_ptr;
struct cb_pcidas_private *devpriv = dev->private;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
@@ -996,7 +983,7 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev,
spin_lock_irqsave(&dev->spinlock, flags);
devpriv->adc_fifo_bits |= INTE;
devpriv->adc_fifo_bits &= ~INT_MASK;
- if (cmd->flags & TRIG_WAKE_EOS) {
+ if (cmd->flags & CMDF_WAKE_EOS) {
if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) {
/* interrupt end of burst */
devpriv->adc_fifo_bits |= INT_EOS;
@@ -1057,7 +1044,7 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct cb_pcidas_board *thisboard = comedi_board(dev);
+ const struct cb_pcidas_board *thisboard = dev->board_ptr;
struct cb_pcidas_private *devpriv = dev->private;
int err = 0;
unsigned int arg;
@@ -1094,7 +1081,9 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_NONE)
+ 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)
@@ -1149,7 +1138,7 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int trig_num)
{
- const struct cb_pcidas_board *thisboard = comedi_board(dev);
+ const struct cb_pcidas_board *thisboard = dev->board_ptr;
struct cb_pcidas_private *devpriv = dev->private;
unsigned int num_bytes, num_points = thisboard->fifo_size;
struct comedi_async *async = s->async;
@@ -1194,7 +1183,7 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
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;
+ unsigned long timer_base = dev->iobase + DAC8254;
i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
@@ -1281,7 +1270,7 @@ static int cb_pcidas_ao_cancel(struct comedi_device *dev,
static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
{
- const struct cb_pcidas_board *thisboard = comedi_board(dev);
+ const struct cb_pcidas_board *thisboard = dev->board_ptr;
struct cb_pcidas_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->write_subdev;
struct comedi_async *async = s->async;
@@ -1336,7 +1325,7 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
{
struct comedi_device *dev = (struct comedi_device *)d;
- const struct cb_pcidas_board *thisboard = comedi_board(dev);
+ const struct cb_pcidas_board *thisboard = dev->board_ptr;
struct cb_pcidas_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async;
@@ -1463,7 +1452,7 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
devpriv->s5933_config = pci_resource_start(pcidev, 0);
devpriv->control_status = pci_resource_start(pcidev, 1);
devpriv->adc_fifo = pci_resource_start(pcidev, 2);
- devpriv->pacer_counter_dio = pci_resource_start(pcidev, 3);
+ dev->iobase = pci_resource_start(pcidev, 3);
if (thisboard->ao_nchan)
devpriv->ao_registers = pci_resource_start(pcidev, 4);
@@ -1512,16 +1501,22 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
*/
s->maxdata = (1 << thisboard->ai_bits) - 1;
s->range_table = &cb_pcidas_ao_ranges;
- s->insn_read = cb_pcidas_ao_readback_insn;
+ /* default to no fifo (*insn_write) */
+ s->insn_write = cb_pcidas_ao_nofifo_winsn;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
+
if (thisboard->has_ao_fifo) {
dev->write_subdev = s;
s->subdev_flags |= SDF_CMD_WRITE;
+ /* use fifo (*insn_write) instead */
s->insn_write = cb_pcidas_ao_fifo_winsn;
s->do_cmdtest = cb_pcidas_ao_cmdtest;
s->do_cmd = cb_pcidas_ao_cmd;
s->cancel = cb_pcidas_ao_cancel;
- } else {
- s->insn_write = cb_pcidas_ao_nofifo_winsn;
}
} else {
s->type = COMEDI_SUBD_UNUSED;
@@ -1529,8 +1524,7 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
/* 8255 */
s = &dev->subdevices[2];
- ret = subdev_8255_init(dev, s, NULL,
- devpriv->pacer_counter_dio + DIO_8255);
+ ret = subdev_8255_init(dev, s, NULL, DIO_8255);
if (ret)
return ret;
@@ -1599,15 +1593,11 @@ static void cb_pcidas_detach(struct comedi_device *dev)
{
struct cb_pcidas_private *devpriv = dev->private;
- if (devpriv) {
- if (devpriv->s5933_config) {
- outl(INTCSR_INBOX_INTR_STATUS,
- devpriv->s5933_config + AMCC_OP_REG_INTCSR);
- }
+ if (devpriv && devpriv->s5933_config) {
+ outl(INTCSR_INBOX_INTR_STATUS,
+ devpriv->s5933_config + AMCC_OP_REG_INTCSR);
}
- if (dev->irq)
- free_irq(dev->irq, dev);
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver cb_pcidas_driver = {
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index fa12614cef2a..3b6bffc66918 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -1038,7 +1038,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
static inline unsigned short se_diff_bit_6xxx(struct comedi_device *dev,
int use_differential)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
if ((thisboard->layout == LAYOUT_64XX && !use_differential) ||
(thisboard->layout == LAYOUT_60XX && use_differential))
@@ -1089,8 +1089,6 @@ struct pcidas64_private {
unsigned int ao_dma_index;
/* number of analog output samples remaining */
unsigned long ao_count;
- /* remember what the analog outputs are set to, to allow readback */
- unsigned int ao_value[2];
unsigned int hw_revision; /* stc chip hardware revision number */
/* last bits sent to INTR_ENABLE_REG register */
unsigned int intr_enable_bits;
@@ -1123,7 +1121,7 @@ struct pcidas64_private {
static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev,
unsigned int range_index)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
const struct comedi_krange *range =
&thisboard->ai_range_table->range[range_index];
unsigned int bits = 0;
@@ -1168,7 +1166,7 @@ static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev,
static unsigned int hw_revision(const struct comedi_device *dev,
uint16_t hw_status_bits)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
if (thisboard->layout == LAYOUT_4020)
return (hw_status_bits >> 13) & 0x7;
@@ -1180,7 +1178,7 @@ static void set_dac_range_bits(struct comedi_device *dev,
uint16_t *bits, unsigned int channel,
unsigned int range)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
unsigned int code = thisboard->ao_range_code[range];
if (channel > 1)
@@ -1237,7 +1235,7 @@ static void disable_ai_interrupts(struct comedi_device *dev)
static void enable_ai_interrupts(struct comedi_device *dev,
const struct comedi_cmd *cmd)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
uint32_t bits;
unsigned long flags;
@@ -1245,8 +1243,8 @@ static void enable_ai_interrupts(struct comedi_device *dev,
bits = EN_ADC_OVERRUN_BIT | EN_ADC_DONE_INTR_BIT |
EN_ADC_ACTIVE_INTR_BIT | EN_ADC_STOP_INTR_BIT;
/* Use pio transfer and interrupt on end of conversion
- * if TRIG_WAKE_EOS flag is set. */
- if (cmd->flags & TRIG_WAKE_EOS) {
+ * if CMDF_WAKE_EOS flag is set. */
+ if (cmd->flags & CMDF_WAKE_EOS) {
/* 4020 doesn't support pio transfers except for fifo dregs */
if (thisboard->layout != LAYOUT_4020)
bits |= ADC_INTR_EOSCAN_BITS | EN_ADC_INTR_SRC_BIT;
@@ -1261,7 +1259,7 @@ static void enable_ai_interrupts(struct comedi_device *dev,
/* initialize plx9080 chip */
static void init_plx9080(struct comedi_device *dev)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
uint32_t bits;
void __iomem *plx_iobase = devpriv->plx9080_iobase;
@@ -1339,7 +1337,7 @@ static void disable_ai_pacing(struct comedi_device *dev)
static int set_ai_fifo_segment_length(struct comedi_device *dev,
unsigned int num_entries)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
static const int increment_size = 0x100;
const struct hw_fifo_info *const fifo = thisboard->ai_fifo;
@@ -1368,7 +1366,7 @@ static int set_ai_fifo_segment_length(struct comedi_device *dev,
/* adjusts the size of hardware fifo (which determines block size for dma xfers) */
static int set_ai_fifo_size(struct comedi_device *dev, unsigned int num_samples)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
unsigned int num_fifo_entries;
int retval;
const struct hw_fifo_info *const fifo = thisboard->ai_fifo;
@@ -1389,7 +1387,7 @@ static int set_ai_fifo_size(struct comedi_device *dev, unsigned int num_samples)
/* query length of fifo */
static unsigned int ai_fifo_size(struct comedi_device *dev)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
return devpriv->ai_fifo_segment_length *
@@ -1399,7 +1397,7 @@ static unsigned int ai_fifo_size(struct comedi_device *dev)
static void init_stc_registers(struct comedi_device *dev)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
uint16_t bits;
unsigned long flags;
@@ -1445,7 +1443,7 @@ static void init_stc_registers(struct comedi_device *dev)
static int alloc_and_init_dma_members(struct comedi_device *dev)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct pcidas64_private *devpriv = dev->private;
int i;
@@ -1526,6 +1524,46 @@ static int alloc_and_init_dma_members(struct comedi_device *dev)
return 0;
}
+static void cb_pcidas64_free_dma(struct comedi_device *dev)
+{
+ const struct pcidas64_board *thisboard = dev->board_ptr;
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct pcidas64_private *devpriv = dev->private;
+ int i;
+
+ if (!devpriv)
+ return;
+
+ /* free pci dma buffers */
+ for (i = 0; i < ai_dma_ring_count(thisboard); i++) {
+ if (devpriv->ai_buffer[i])
+ pci_free_consistent(pcidev,
+ DMA_BUFFER_SIZE,
+ devpriv->ai_buffer[i],
+ devpriv->ai_buffer_bus_addr[i]);
+ }
+ for (i = 0; i < AO_DMA_RING_COUNT; i++) {
+ if (devpriv->ao_buffer[i])
+ pci_free_consistent(pcidev,
+ DMA_BUFFER_SIZE,
+ devpriv->ao_buffer[i],
+ devpriv->ao_buffer_bus_addr[i]);
+ }
+ /* free dma descriptors */
+ if (devpriv->ai_dma_desc)
+ pci_free_consistent(pcidev,
+ sizeof(struct plx_dma_desc) *
+ ai_dma_ring_count(thisboard),
+ devpriv->ai_dma_desc,
+ devpriv->ai_dma_desc_bus_addr);
+ if (devpriv->ao_dma_desc)
+ pci_free_consistent(pcidev,
+ sizeof(struct plx_dma_desc) *
+ AO_DMA_RING_COUNT,
+ devpriv->ao_dma_desc,
+ devpriv->ao_dma_desc_bus_addr);
+}
+
static inline void warn_external_queue(struct comedi_device *dev)
{
dev_err(dev->class_dev,
@@ -1668,7 +1706,7 @@ static int cb_pcidas64_ai_eoc(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned long context)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
unsigned int status;
@@ -1687,7 +1725,7 @@ static int cb_pcidas64_ai_eoc(struct comedi_device *dev,
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);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
unsigned int bits = 0, n;
unsigned int channel, range, aref;
@@ -1807,7 +1845,7 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
static int ai_config_calibration_source(struct comedi_device *dev,
unsigned int *data)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
unsigned int source = data[1];
int num_calibration_sources;
@@ -1829,7 +1867,7 @@ static int ai_config_calibration_source(struct comedi_device *dev,
static int ai_config_block_size(struct comedi_device *dev, unsigned int *data)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
int fifo_size;
const struct hw_fifo_info *const fifo = thisboard->ai_fifo;
unsigned int block_size, requested_block_size;
@@ -1883,7 +1921,7 @@ static int ai_config_master_clock_4020(struct comedi_device *dev,
/* XXX could add support for 60xx series */
static int ai_config_master_clock(struct comedi_device *dev, unsigned int *data)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
switch (thisboard->layout) {
case LAYOUT_4020:
@@ -1920,14 +1958,14 @@ static unsigned int get_divisor(unsigned int ns, unsigned int flags)
{
unsigned int divisor;
- switch (flags & TRIG_ROUND_MASK) {
- case TRIG_ROUND_UP:
+ switch (flags & CMDF_ROUND_MASK) {
+ case CMDF_ROUND_UP:
divisor = (ns + TIMER_BASE - 1) / TIMER_BASE;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
divisor = ns / TIMER_BASE;
break;
- case TRIG_ROUND_NEAREST:
+ case CMDF_ROUND_NEAREST:
default:
divisor = (ns + TIMER_BASE / 2) / TIMER_BASE;
break;
@@ -1941,7 +1979,7 @@ static unsigned int get_divisor(unsigned int ns, unsigned int flags)
*/
static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
unsigned int convert_divisor = 0, scan_divisor;
static const int min_convert_divisor = 3;
static const int max_convert_divisor =
@@ -1989,7 +2027,7 @@ 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);
+ const struct pcidas64_board *board = dev->board_ptr;
unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
int i;
@@ -2028,7 +2066,7 @@ static int cb_pcidas64_ai_check_chanlist(struct comedi_device *dev,
static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
int err = 0;
unsigned int tmp_arg, tmp_arg2;
unsigned int triggers;
@@ -2178,7 +2216,7 @@ static void setup_sample_counters(struct comedi_device *dev,
static inline unsigned int dma_transfer_size(struct comedi_device *dev)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
unsigned int num_samples;
@@ -2265,7 +2303,7 @@ static void select_master_clock_4020(struct comedi_device *dev,
static void select_master_clock(struct comedi_device *dev,
const struct comedi_cmd *cmd)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
switch (thisboard->layout) {
case LAYOUT_4020:
@@ -2297,7 +2335,7 @@ static inline void dma_start_sync(struct comedi_device *dev,
static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
uint32_t convert_counter = 0, scan_counter = 0;
@@ -2346,7 +2384,7 @@ static int use_internal_queue_6xxx(const struct comedi_cmd *cmd)
static int setup_channel_queue(struct comedi_device *dev,
const struct comedi_cmd *cmd)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
unsigned short bits;
int i;
@@ -2483,7 +2521,7 @@ static inline void load_first_dma_descriptor(struct comedi_device *dev,
static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
@@ -2541,7 +2579,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* clear adc buffer */
writew(0, devpriv->main_iobase + ADC_BUFFER_CLEAR_REG);
- if ((cmd->flags & TRIG_WAKE_EOS) == 0 ||
+ if ((cmd->flags & CMDF_WAKE_EOS) == 0 ||
thisboard->layout == LAYOUT_4020) {
devpriv->ai_dma_index = 0;
@@ -2575,7 +2613,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* enable pacing, triggering, etc */
bits = ADC_ENABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT;
- if (cmd->flags & TRIG_WAKE_EOS)
+ if (cmd->flags & CMDF_WAKE_EOS)
bits |= ADC_DMA_DISABLE_BIT;
/* set start trigger */
if (cmd->start_src == TRIG_EXT) {
@@ -2700,7 +2738,7 @@ static void pio_drain_ai_fifo_32(struct comedi_device *dev)
/* empty fifo */
static void pio_drain_ai_fifo(struct comedi_device *dev)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
if (thisboard->layout == LAYOUT_4020)
pio_drain_ai_fifo_32(dev);
@@ -2710,7 +2748,7 @@ static void pio_drain_ai_fifo(struct comedi_device *dev)
static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
struct comedi_async *async = dev->read_subdev->async;
struct comedi_cmd *cmd = &async->cmd;
@@ -2755,7 +2793,7 @@ static void handle_ai_interrupt(struct comedi_device *dev,
unsigned short status,
unsigned int plx_status)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async = s->async;
@@ -2782,7 +2820,7 @@ static void handle_ai_interrupt(struct comedi_device *dev,
/* drain fifo with pio */
if ((status & ADC_DONE_BIT) ||
- ((cmd->flags & TRIG_WAKE_EOS) &&
+ ((cmd->flags & CMDF_WAKE_EOS) &&
(status & ADC_INTR_PENDING_BIT) &&
(thisboard->layout != LAYOUT_4020))) {
spin_lock_irqsave(&dev->spinlock, flags);
@@ -3037,7 +3075,7 @@ static int ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
int chan = CR_CHAN(insn->chanspec);
int range = CR_RANGE(insn->chanspec);
@@ -3061,18 +3099,7 @@ static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
}
/* remember output value */
- devpriv->ao_value[chan] = data[0];
-
- return 1;
-}
-
-static int ao_readback_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct pcidas64_private *devpriv = dev->private;
-
- data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)];
+ s->readback[chan] = data[0];
return 1;
}
@@ -3200,7 +3227,7 @@ 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);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
if (s->busy)
return 0;
@@ -3284,7 +3311,7 @@ static int cb_pcidas64_ao_check_chanlist(struct comedi_device *dev,
static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
int err = 0;
unsigned int tmp_arg;
@@ -3369,26 +3396,16 @@ static int ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
-static int dio_callback(int dir, int port, int data, unsigned long arg)
-{
- void __iomem *iobase = (void __iomem *)arg;
-
- if (dir) {
- writeb(data, iobase + port);
- return 0;
- }
- return readb(iobase + port);
-}
-
-static int dio_callback_4020(int dir, int port, int data, unsigned long arg)
+static int dio_callback_4020(struct comedi_device *dev,
+ int dir, int port, int data, unsigned long iobase)
{
- void __iomem *iobase = (void __iomem *)arg;
+ struct pcidas64_private *devpriv = dev->private;
if (dir) {
- writew(data, iobase + 2 * port);
+ writew(data, devpriv->main_iobase + iobase + 2 * port);
return 0;
}
- return readw(iobase + 2 * port);
+ return readw(devpriv->main_iobase + iobase + 2 * port);
}
static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -3562,7 +3579,7 @@ static int caldac_i2c_write(struct comedi_device *dev,
static void caldac_write(struct comedi_device *dev, unsigned int channel,
unsigned int value)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
devpriv->caldac_state[channel] = value;
@@ -3748,10 +3765,9 @@ static int eeprom_read_insn(struct comedi_device *dev,
*/
static int setup_subdevices(struct comedi_device *dev)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
+ const struct pcidas64_board *thisboard = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
struct comedi_subdevice *s;
- void __iomem *dio_8255_iobase;
int i;
int ret;
@@ -3799,8 +3815,13 @@ static int setup_subdevices(struct comedi_device *dev)
s->n_chan = thisboard->ao_nchan;
s->maxdata = (1 << thisboard->ao_bits) - 1;
s->range_table = thisboard->ao_range_table;
- s->insn_read = ao_readback_insn;
s->insn_write = ao_winsn;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
+
if (ao_cmd_is_supported(thisboard)) {
dev->write_subdev = s;
s->do_cmdtest = ao_cmdtest;
@@ -3840,13 +3861,11 @@ static int setup_subdevices(struct comedi_device *dev)
s = &dev->subdevices[4];
if (thisboard->has_8255) {
if (thisboard->layout == LAYOUT_4020) {
- dio_8255_iobase = devpriv->main_iobase + I8255_4020_REG;
ret = subdev_8255_init(dev, s, dio_callback_4020,
- (unsigned long)dio_8255_iobase);
+ I8255_4020_REG);
} else {
- dio_8255_iobase = dev->mmio + DIO_8255_OFFSET;
- ret = subdev_8255_init(dev, s, dio_callback,
- (unsigned long)dio_8255_iobase);
+ ret = subdev_8255_mm_init(dev, s, NULL,
+ DIO_8255_OFFSET);
}
if (ret)
return ret;
@@ -3996,54 +4015,22 @@ static int auto_attach(struct comedi_device *dev,
static void detach(struct comedi_device *dev)
{
- const struct pcidas64_board *thisboard = comedi_board(dev);
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct pcidas64_private *devpriv = dev->private;
- unsigned int i;
if (dev->irq)
free_irq(dev->irq, dev);
if (devpriv) {
- if (pcidev) {
- if (devpriv->plx9080_iobase) {
- disable_plx_interrupts(dev);
- iounmap(devpriv->plx9080_iobase);
- }
- if (devpriv->main_iobase)
- iounmap(devpriv->main_iobase);
- if (dev->mmio)
- iounmap(dev->mmio);
- /* free pci dma buffers */
- for (i = 0; i < ai_dma_ring_count(thisboard); i++) {
- if (devpriv->ai_buffer[i])
- pci_free_consistent(pcidev,
- DMA_BUFFER_SIZE,
- devpriv->ai_buffer[i],
- devpriv->ai_buffer_bus_addr[i]);
- }
- for (i = 0; i < AO_DMA_RING_COUNT; i++) {
- if (devpriv->ao_buffer[i])
- pci_free_consistent(pcidev,
- DMA_BUFFER_SIZE,
- devpriv->ao_buffer[i],
- devpriv->ao_buffer_bus_addr[i]);
- }
- /* free dma descriptors */
- if (devpriv->ai_dma_desc)
- pci_free_consistent(pcidev,
- sizeof(struct plx_dma_desc) *
- ai_dma_ring_count(thisboard),
- devpriv->ai_dma_desc,
- devpriv->ai_dma_desc_bus_addr);
- if (devpriv->ao_dma_desc)
- pci_free_consistent(pcidev,
- sizeof(struct plx_dma_desc) *
- AO_DMA_RING_COUNT,
- devpriv->ao_dma_desc,
- devpriv->ao_dma_desc_bus_addr);
+ if (devpriv->plx9080_iobase) {
+ disable_plx_interrupts(dev);
+ iounmap(devpriv->plx9080_iobase);
}
+ if (devpriv->main_iobase)
+ iounmap(devpriv->main_iobase);
+ if (dev->mmio)
+ iounmap(dev->mmio);
}
comedi_pci_disable(dev);
+ cb_pcidas64_free_dma(dev);
}
static struct comedi_driver cb_pcidas64_driver = {
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index 901dc5d1bb72..01875d7c376f 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -154,6 +154,7 @@ static const struct cb_pcidda_board cb_pcidda_boards[] = {
};
struct cb_pcidda_private {
+ unsigned long daqio;
/* bits last written to da calibration register 1 */
unsigned int dac_cal1_bits;
/* current range settings for output channels */
@@ -164,13 +165,14 @@ struct cb_pcidda_private {
/* lowlevel read from eeprom */
static unsigned int cb_pcidda_serial_in(struct comedi_device *dev)
{
+ struct cb_pcidda_private *devpriv = dev->private;
unsigned int value = 0;
int i;
const int value_width = 16; /* number of bits wide values are */
for (i = 1; i <= value_width; i++) {
/* read bits most significant bit first */
- if (inw_p(dev->iobase + DACALIBRATION1) & SERIAL_OUT_BIT)
+ if (inw_p(devpriv->daqio + DACALIBRATION1) & SERIAL_OUT_BIT)
value |= 1 << (value_width - i);
}
@@ -190,7 +192,7 @@ static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value,
devpriv->dac_cal1_bits |= SERIAL_IN_BIT;
else
devpriv->dac_cal1_bits &= ~SERIAL_IN_BIT;
- outw_p(devpriv->dac_cal1_bits, dev->iobase + DACALIBRATION1);
+ outw_p(devpriv->dac_cal1_bits, devpriv->daqio + DACALIBRATION1);
}
}
@@ -198,6 +200,7 @@ static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value,
static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
unsigned int address)
{
+ struct cb_pcidda_private *devpriv = dev->private;
unsigned int i;
unsigned int cal2_bits;
unsigned int value;
@@ -213,7 +216,7 @@ static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
/* deactivate caldacs (one caldac for every two channels) */
for (i = 0; i < max_num_caldacs; i++)
cal2_bits |= DESELECT_CALDAC_BIT(i);
- outw_p(cal2_bits, dev->iobase + DACALIBRATION2);
+ outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2);
/* tell eeprom we want to read */
cb_pcidda_serial_out(dev, read_instruction, instruction_length);
@@ -224,7 +227,7 @@ static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
/* deactivate eeprom */
cal2_bits &= ~SELECT_EEPROM_BIT;
- outw_p(cal2_bits, dev->iobase + DACALIBRATION2);
+ outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2);
return value;
}
@@ -234,6 +237,7 @@ static void cb_pcidda_write_caldac(struct comedi_device *dev,
unsigned int caldac, unsigned int channel,
unsigned int value)
{
+ struct cb_pcidda_private *devpriv = dev->private;
unsigned int cal2_bits;
unsigned int i;
/* caldacs use 3 bit channel specification */
@@ -256,10 +260,10 @@ static void cb_pcidda_write_caldac(struct comedi_device *dev,
cal2_bits |= DESELECT_CALDAC_BIT(i);
/* activate the caldac we want */
cal2_bits &= ~DESELECT_CALDAC_BIT(caldac);
- outw_p(cal2_bits, dev->iobase + DACALIBRATION2);
+ outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2);
/* deactivate caldac */
cal2_bits |= DESELECT_CALDAC_BIT(caldac);
- outw_p(cal2_bits, dev->iobase + DACALIBRATION2);
+ outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2);
}
/* set caldacs to eeprom values for given channel and range */
@@ -324,9 +328,9 @@ static int cb_pcidda_ao_insn_write(struct comedi_device *dev,
if (range > 2)
ctrl |= CB_DDA_DA_CTRL_UNIP;
- outw(ctrl, dev->iobase + CB_DDA_DA_CTRL_REG);
+ outw(ctrl, devpriv->daqio + CB_DDA_DA_CTRL_REG);
- outw(data[0], dev->iobase + CB_DDA_DA_DATA_REG(channel));
+ outw(data[0], devpriv->daqio + CB_DDA_DA_DATA_REG(channel));
return insn->n;
}
@@ -338,7 +342,6 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev,
const struct cb_pcidda_board *thisboard = NULL;
struct cb_pcidda_private *devpriv;
struct comedi_subdevice *s;
- unsigned long iobase_8255;
int i;
int ret;
@@ -356,8 +359,8 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev,
ret = comedi_pci_enable(dev);
if (ret)
return ret;
- dev->iobase = pci_resource_start(pcidev, 3);
- iobase_8255 = pci_resource_start(pcidev, 2);
+ dev->iobase = pci_resource_start(pcidev, 2);
+ devpriv->daqio = pci_resource_start(pcidev, 3);
ret = comedi_alloc_subdevices(dev, 3);
if (ret)
@@ -375,7 +378,7 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev,
/* two 8255 digital io subdevices */
for (i = 0; i < 2; i++) {
s = &dev->subdevices[1 + i];
- ret = subdev_8255_init(dev, s, NULL, iobase_8255 + (i * 4));
+ ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE);
if (ret)
return ret;
}
@@ -395,7 +398,7 @@ static struct comedi_driver cb_pcidda_driver = {
.driver_name = "cb_pcidda",
.module = THIS_MODULE,
.auto_attach = cb_pcidda_auto_attach,
- .detach = comedi_pci_disable,
+ .detach = comedi_pci_detach,
};
static int cb_pcidda_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index ccb9c72bc0c3..fe4d2544f3dc 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -77,10 +77,8 @@ See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details.
*/
struct cb_pcimdas_private {
/* base addresses */
+ unsigned long daqio;
unsigned long BADR3;
-
- /* Used for AO readback */
- unsigned int ao_readback[2];
};
static int cb_pcimdas_ai_eoc(struct comedi_device *dev,
@@ -143,7 +141,7 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
/* convert n samples */
for (n = 0; n < insn->n; n++) {
/* trigger conversion */
- outw(0, dev->iobase + 0);
+ outw(0, devpriv->daqio + 0);
/* wait for conversion to end */
ret = comedi_timeout(dev, s, insn, cb_pcimdas_ai_eoc, 0);
@@ -151,55 +149,31 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
return ret;
/* read data */
- data[n] = inw(dev->iobase + 0);
+ data[n] = inw(devpriv->daqio + 0);
}
/* return the number of samples read/written */
return n;
}
-static int cb_pcimdas_ao_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int cb_pcimdas_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct cb_pcimdas_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = s->readback[chan];
+ unsigned int reg = (chan) ? DAC1_OFFSET : DAC0_OFFSET;
int i;
- int chan = CR_CHAN(insn->chanspec);
- /* Writing a list of values to an AO channel is probably not
- * very useful, but that's how the interface is defined. */
for (i = 0; i < insn->n; i++) {
- switch (chan) {
- case 0:
- outw(data[i] & 0x0FFF, dev->iobase + DAC0_OFFSET);
- break;
- case 1:
- outw(data[i] & 0x0FFF, dev->iobase + DAC1_OFFSET);
- break;
- default:
- return -1;
- }
- devpriv->ao_readback[chan] = data[i];
+ val = data[i];
+ outw(val, devpriv->daqio + reg);
}
+ s->readback[chan] = val;
- /* return the number of samples read/written */
- return i;
-}
-
-/* AO subdevices should have a read insn as well as a write insn.
- * Usually this means copying a value stored in devpriv. */
-static int cb_pcimdas_ao_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct cb_pcimdas_private *devpriv = dev->private;
- int i;
- int chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return i;
+ return insn->n;
}
static int cb_pcimdas_auto_attach(struct comedi_device *dev,
@@ -208,7 +182,6 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev,
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct cb_pcimdas_private *devpriv;
struct comedi_subdevice *s;
- unsigned long iobase_8255;
int ret;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
@@ -219,9 +192,9 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
- dev->iobase = pci_resource_start(pcidev, 2);
+ devpriv->daqio = pci_resource_start(pcidev, 2);
devpriv->BADR3 = pci_resource_start(pcidev, 3);
- iobase_8255 = pci_resource_start(pcidev, 4);
+ dev->iobase = pci_resource_start(pcidev, 4);
ret = comedi_alloc_subdevices(dev, 3);
if (ret)
@@ -247,30 +220,27 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev,
s->maxdata = 0xfff;
/* ranges are hardware settable, but not software readable. */
s->range_table = &range_unknown;
- s->insn_write = &cb_pcimdas_ao_winsn;
- s->insn_read = &cb_pcimdas_ao_rinsn;
+ s->insn_write = cb_pcimdas_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[2];
/* digital i/o subdevice */
- ret = subdev_8255_init(dev, s, NULL, iobase_8255);
+ ret = subdev_8255_init(dev, s, NULL, 0x00);
if (ret)
return ret;
return 0;
}
-static void cb_pcimdas_detach(struct comedi_device *dev)
-{
- if (dev->irq)
- free_irq(dev->irq, dev);
- comedi_pci_disable(dev);
-}
-
static struct comedi_driver cb_pcimdas_driver = {
.driver_name = "cb_pcimdas",
.module = THIS_MODULE,
.auto_attach = cb_pcimdas_auto_attach,
- .detach = cb_pcimdas_detach,
+ .detach = comedi_pci_detach,
};
static int cb_pcimdas_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index 4a2b200de01b..03043e7b9b58 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdda.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdda.c
@@ -90,21 +90,14 @@ Configuration Options: not applicable, uses PCI auto config
#define PCIMDDA_DA_CHAN(x) (0x00 + (x) * 2)
#define PCIMDDA_8255_BASE_REG 0x0c
-#define MAX_AO_READBACK_CHANNELS 6
-
-struct cb_pcimdda_private {
- unsigned int ao_readback[MAX_AO_READBACK_CHANNELS];
-};
-
-static int cb_pcimdda_ao_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int cb_pcimdda_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct cb_pcimdda_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned long offset = dev->iobase + PCIMDDA_DA_CHAN(chan);
- unsigned int val = 0;
+ unsigned int val = s->readback[chan];
int i;
for (i = 0; i < insn->n; i++) {
@@ -122,45 +115,31 @@ static int cb_pcimdda_ao_winsn(struct comedi_device *dev,
outb(val & 0x00ff, offset);
outb((val >> 8) & 0x00ff, offset + 1);
}
-
- /* Cache the last value for readback */
- devpriv->ao_readback[chan] = val;
+ s->readback[chan] = val;
return insn->n;
}
-static int cb_pcimdda_ao_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int cb_pcimdda_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct cb_pcimdda_private *devpriv = dev->private;
- int chan = CR_CHAN(insn->chanspec);
- unsigned long offset = dev->iobase + PCIMDDA_DA_CHAN(chan);
- int i;
-
- for (i = 0; i < insn->n; i++) {
- /* Initiate the simultaneous transfer */
- inw(offset);
+ unsigned int chan = CR_CHAN(insn->chanspec);
- data[i] = devpriv->ao_readback[chan];
- }
+ /* Initiate the simultaneous transfer */
+ inw(dev->iobase + PCIMDDA_DA_CHAN(chan));
- return insn->n;
+ return comedi_readback_insn_read(dev, s, insn, data);
}
static int cb_pcimdda_auto_attach(struct comedi_device *dev,
unsigned long context_unused)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- struct cb_pcimdda_private *devpriv;
struct comedi_subdevice *s;
int ret;
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
ret = comedi_pci_enable(dev);
if (ret)
return ret;
@@ -177,13 +156,16 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev,
s->n_chan = 6;
s->maxdata = 0xffff;
s->range_table = &range_bipolar5;
- s->insn_write = cb_pcimdda_ao_winsn;
- s->insn_read = cb_pcimdda_ao_rinsn;
+ s->insn_write = cb_pcimdda_ao_insn_write;
+ s->insn_read = cb_pcimdda_ao_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[1];
/* digital i/o subdevice */
- ret = subdev_8255_init(dev, s, NULL,
- dev->iobase + PCIMDDA_8255_BASE_REG);
+ ret = subdev_8255_init(dev, s, NULL, PCIMDDA_8255_BASE_REG);
if (ret)
return ret;
@@ -194,7 +176,7 @@ static struct comedi_driver cb_pcimdda_driver = {
.driver_name = "cb_pcimdda",
.module = THIS_MODULE,
.auto_attach = cb_pcimdda_auto_attach,
- .detach = comedi_pci_disable,
+ .detach = comedi_pci_detach,
};
static int cb_pcimdda_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c
deleted file mode 100644
index c33c3e5680a6..000000000000
--- a/drivers/staging/comedi/drivers/comedi_fc.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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"
-
-unsigned int cfc_bytes_per_scan(struct comedi_subdevice *s)
-{
- 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) {
- async->scan_progress %= scan_length;
- 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 *s,
- void *data, unsigned int num_bytes)
-{
- struct comedi_async *async = s->async;
- unsigned int retval;
-
- if (num_bytes == 0)
- return 0;
-
- retval = comedi_buf_write_alloc(s, num_bytes);
- if (retval != num_bytes) {
- dev_warn(s->device->class_dev, "buffer overrun\n");
- async->events |= COMEDI_CB_OVERFLOW;
- return 0;
- }
-
- 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 *s,
- void *data, unsigned int num_bytes)
-{
- if (num_bytes == 0)
- return 0;
-
- 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 *s)
-{
- unsigned int events = s->async->events;
-
- if (events == 0)
- return events;
-
- if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW))
- s->cancel(dev, s);
-
- comedi_event(dev, s);
-
- return events;
-}
-EXPORT_SYMBOL_GPL(cfc_handle_events);
-
-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_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 541b9371d3da..ce2835972507 100644
--- a/drivers/staging/comedi/drivers/comedi_fc.h
+++ b/drivers/staging/comedi/drivers/comedi_fc.h
@@ -23,30 +23,48 @@
#include "../comedidev.h"
-unsigned int cfc_bytes_per_scan(struct comedi_subdevice *);
-void cfc_inc_scan_progress(struct comedi_subdevice *, unsigned int num_bytes);
+static inline unsigned int cfc_bytes_per_scan(struct comedi_subdevice *s)
+{
+ return comedi_bytes_per_scan(s);
+}
-/* Writes an array of data points to comedi's buffer */
-unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *,
- void *data, unsigned int num_bytes);
+static inline void cfc_inc_scan_progress(struct comedi_subdevice *s,
+ unsigned int num_bytes)
+{
+ comedi_inc_scan_progress(s, num_bytes);
+}
+
+static inline unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *s,
+ const void *data,
+ unsigned int num_bytes)
+{
+ return comedi_write_array_to_buffer(s, data, num_bytes);
+}
static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *s,
unsigned short data)
{
- return cfc_write_array_to_buffer(s, &data, sizeof(data));
+ return comedi_write_array_to_buffer(s, &data, sizeof(data));
};
static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice *s,
unsigned int data)
{
- return cfc_write_array_to_buffer(s, &data, sizeof(data));
+ return comedi_write_array_to_buffer(s, &data, sizeof(data));
};
-unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *,
- void *data, unsigned int num_bytes);
+static inline unsigned int
+cfc_read_array_from_buffer(struct comedi_subdevice *s, void *data,
+ unsigned int num_bytes)
+{
+ return comedi_read_array_from_buffer(s, data, num_bytes);
+}
-unsigned int cfc_handle_events(struct comedi_device *,
- struct comedi_subdevice *);
+static inline unsigned int cfc_handle_events(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ return comedi_handle_events(dev, s);
+}
/**
* 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 a42748692357..bf002988192d 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -173,9 +173,6 @@ static int parport_intr_cmdtest(struct comedi_device *dev,
/* Step 2a : make sure trigger sources are unique */
/* 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);
@@ -187,10 +184,9 @@ static int parport_intr_cmdtest(struct comedi_device *dev,
if (err)
return 3;
- /* step 4: ignored */
+ /* Step 4: fix up any arguments */
- if (err)
- return 4;
+ /* Step 5: check channel list if it exists */
return 0;
}
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c
index 845a67905ca6..00c03df72523 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -302,7 +302,7 @@ static int waveform_ai_cmd(struct comedi_device *dev,
struct waveform_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
- if (cmd->flags & TRIG_RT) {
+ if (cmd->flags & CMDF_PRIORITY) {
dev_err(dev->class_dev,
"commands at RT priority not supported in this driver\n");
return -1;
@@ -415,14 +415,14 @@ static int waveform_attach(struct comedi_device *dev,
for (i = 0; i < s->n_chan; i++)
devpriv->ao_loopbacks[i] = s->maxdata / 2;
- init_timer(&(devpriv->timer));
+ init_timer(&devpriv->timer);
devpriv->timer.function = waveform_ai_interrupt;
devpriv->timer.data = (unsigned long)dev;
dev_info(dev->class_dev,
- "%s: %i microvolt, %li microsecond waveform attached\n",
- dev->board_name,
- devpriv->uvolt_amplitude, devpriv->usec_period);
+ "%s: %i microvolt, %li microsecond waveform attached\n",
+ dev->board_name,
+ devpriv->uvolt_amplitude, devpriv->usec_period);
return 0;
}
diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c
index f066fb06dc1d..205f9df345a2 100644
--- a/drivers/staging/comedi/drivers/contec_pci_dio.c
+++ b/drivers/staging/comedi/drivers/contec_pci_dio.c
@@ -97,7 +97,7 @@ static struct comedi_driver contec_pci_dio_driver = {
.driver_name = "contec_pci_dio",
.module = THIS_MODULE,
.auto_attach = contec_auto_attach,
- .detach = comedi_pci_disable,
+ .detach = comedi_pci_detach,
};
static int contec_pci_dio_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c
index df46e0a5bade..34cbe83f0ce7 100644
--- a/drivers/staging/comedi/drivers/dac02.c
+++ b/drivers/staging/comedi/drivers/dac02.c
@@ -68,10 +68,6 @@ static const struct comedi_lrange das02_ao_ranges = {
}
};
-struct dac02_private {
- unsigned int ao_readback[2];
-};
-
/*
* Register I/O map
*/
@@ -83,7 +79,6 @@ static int dac02_ao_insn_write(struct comedi_device *dev,
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;
@@ -92,7 +87,7 @@ static int dac02_ao_insn_write(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
val = data[i];
- devpriv->ao_readback[chan] = val;
+ s->readback[chan] = val;
/*
* Unipolar outputs are true binary encoding.
@@ -113,31 +108,11 @@ static int dac02_ao_insn_write(struct comedi_device *dev,
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;
@@ -154,7 +129,11 @@ static int dac02_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->maxdata = 0x0fff;
s->range_table = &das02_ao_ranges;
s->insn_write = dac02_ao_insn_write;
- s->insn_read = dac02_ao_insn_read;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
return 0;
}
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index cd369cd40114..e5b5a8133b34 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -275,7 +275,6 @@ struct daqboard2000_private {
card_daqboard_2000
} card;
void __iomem *plx;
- unsigned int ao_readback[2];
};
static void writeAcqScanListEntry(struct comedi_device *dev, u16 entry)
@@ -401,21 +400,6 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev,
return i;
}
-static int daqboard2000_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct daqboard2000_private *devpriv = dev->private;
- int chan = CR_CHAN(insn->chanspec);
- int i;
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return i;
-}
-
static int daqboard2000_ao_eoc(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -435,38 +419,23 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- struct daqboard2000_private *devpriv = dev->private;
- int chan = CR_CHAN(insn->chanspec);
- int ret;
+ unsigned int chan = CR_CHAN(insn->chanspec);
int i;
for (i = 0; i < insn->n; i++) {
-#if 0
- /*
- * OK, since it works OK without enabling the DAC's,
- * let's keep it as simple as possible...
- */
- writew((chan + 2) * 0x0010 | 0x0001, dev->mmio + dacControl);
- udelay(1000);
-#endif
- writew(data[i], dev->mmio + dacSetting(chan));
+ unsigned int val = data[i];
+ int ret;
+
+ writew(val, dev->mmio + dacSetting(chan));
ret = comedi_timeout(dev, s, insn, daqboard2000_ao_eoc, 0);
if (ret)
return ret;
- devpriv->ao_readback[chan] = data[i];
-#if 0
- /*
- * Since we never enabled the DAC's, we don't need
- * to disable it...
- */
- writew((chan + 2) * 0x0010 | 0x0000, dev->mmio + dacControl);
- udelay(1000);
-#endif
+ s->readback[chan] = val;
}
- return i;
+ return insn->n;
}
static void daqboard2000_resetLocalBus(struct comedi_device *dev)
@@ -651,16 +620,15 @@ static void daqboard2000_initializeDac(struct comedi_device *dev)
daqboard2000_dacDisarm(dev);
}
-static int daqboard2000_8255_cb(int dir, int port, int data,
- unsigned long ioaddr)
+static int daqboard2000_8255_cb(struct comedi_device *dev,
+ int dir, int port, int data,
+ unsigned long iobase)
{
- void __iomem *mmio_base = (void __iomem *)ioaddr;
-
if (dir) {
- writew(data, mmio_base + port * 2);
+ writew(data, dev->mmio + iobase + port * 2);
return 0;
}
- return readw(mmio_base + port * 2);
+ return readw(dev->mmio + iobase + port * 2);
}
static const void *daqboard2000_find_boardinfo(struct comedi_device *dev,
@@ -738,13 +706,17 @@ static int daqboard2000_auto_attach(struct comedi_device *dev,
s->subdev_flags = SDF_WRITABLE;
s->n_chan = 2;
s->maxdata = 0xffff;
- s->insn_read = daqboard2000_ao_insn_read;
s->insn_write = daqboard2000_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
s->range_table = &range_bipolar10;
+ result = comedi_alloc_subdev_readback(s);
+ if (result)
+ return result;
+
s = &dev->subdevices[2];
result = subdev_8255_init(dev, s, daqboard2000_8255_cb,
- (unsigned long)(dev->mmio + dioP2ExpansionIO8Bit));
+ dioP2ExpansionIO8Bit);
if (result)
return result;
@@ -755,15 +727,9 @@ static void daqboard2000_detach(struct comedi_device *dev)
{
struct daqboard2000_private *devpriv = dev->private;
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (devpriv) {
- if (dev->mmio)
- iounmap(dev->mmio);
- if (devpriv->plx)
- iounmap(devpriv->plx);
- }
- comedi_pci_disable(dev);
+ if (devpriv && devpriv->plx)
+ iounmap(devpriv->plx);
+ comedi_pci_detach(dev);
}
static struct comedi_driver daqboard2000_driver = {
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index fcf916a80c8d..bdb671a66e22 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -217,7 +217,7 @@ static int das08_ai_eoc(struct comedi_device *dev,
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);
+ const struct das08_board_struct *thisboard = dev->board_ptr;
struct das08_private_struct *devpriv = dev->private;
int n;
int chan;
@@ -337,8 +337,7 @@ static int das08jr_do_wbits(struct comedi_device *dev,
static void das08_ao_set_data(struct comedi_device *dev,
unsigned int chan, unsigned int data)
{
- const struct das08_board_struct *thisboard = comedi_board(dev);
- struct das08_private_struct *devpriv = dev->private;
+ const struct das08_board_struct *thisboard = dev->board_ptr;
unsigned char lsb;
unsigned char msb;
@@ -355,54 +354,29 @@ static void das08_ao_set_data(struct comedi_device *dev,
/* load DACs */
inb(dev->iobase + DAS08AO_AO_UPDATE);
}
- devpriv->ao_readback[chan] = data;
-}
-
-static void das08_ao_initialize(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- int n;
- unsigned int data;
-
- data = s->maxdata / 2; /* should be about 0 volts */
- for (n = 0; n < s->n_chan; n++)
- das08_ao_set_data(dev, n, data);
-}
-
-static int das08_ao_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- unsigned int n;
- unsigned int chan;
-
- chan = CR_CHAN(insn->chanspec);
-
- for (n = 0; n < insn->n; n++)
- das08_ao_set_data(dev, chan, *data);
-
- return n;
}
-static int das08_ao_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int das08_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct das08_private_struct *devpriv = dev->private;
- unsigned int n;
- unsigned int chan;
-
- chan = CR_CHAN(insn->chanspec);
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = s->readback[chan];
+ int i;
- for (n = 0; n < insn->n; n++)
- data[n] = devpriv->ao_readback[chan];
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+ das08_ao_set_data(dev, chan, val);
+ }
+ s->readback[chan] = val;
- return n;
+ return insn->n;
}
static void i8254_initialize(struct comedi_device *dev)
{
- const struct das08_board_struct *thisboard = comedi_board(dev);
+ const struct das08_board_struct *thisboard = dev->board_ptr;
unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
unsigned int mode = I8254_MODE0 | I8254_BINARY;
int i;
@@ -415,7 +389,7 @@ static int das08_counter_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- const struct das08_board_struct *thisboard = comedi_board(dev);
+ const struct das08_board_struct *thisboard = dev->board_ptr;
unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
int chan = insn->chanspec;
@@ -427,7 +401,7 @@ static int das08_counter_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- const struct das08_board_struct *thisboard = comedi_board(dev);
+ const struct das08_board_struct *thisboard = dev->board_ptr;
unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
int chan = insn->chanspec;
@@ -439,7 +413,7 @@ static int das08_counter_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- const struct das08_board_struct *thisboard = comedi_board(dev);
+ const struct das08_board_struct *thisboard = dev->board_ptr;
unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset;
int chan = insn->chanspec;
@@ -458,10 +432,11 @@ static int das08_counter_config(struct comedi_device *dev,
int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
{
- const struct das08_board_struct *thisboard = comedi_board(dev);
+ const struct das08_board_struct *thisboard = dev->board_ptr;
struct das08_private_struct *devpriv = dev->private;
struct comedi_subdevice *s;
int ret;
+ int i;
dev->iobase = iobase;
@@ -498,9 +473,18 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
s->n_chan = 2;
s->maxdata = (1 << thisboard->ao_nbits) - 1;
s->range_table = &range_bipolar5;
- s->insn_write = das08_ao_winsn;
- s->insn_read = das08_ao_rinsn;
- das08_ao_initialize(dev, s);
+ s->insn_write = das08_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
+
+ /* intialize all channels to 0V */
+ for (i = 0; i < s->n_chan; i++) {
+ s->readback[i] = s->maxdata / 2;
+ das08_ao_set_data(dev, i, s->readback[i]);
+ }
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -536,8 +520,7 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
s = &dev->subdevices[4];
/* 8255 */
if (thisboard->i8255_offset != 0) {
- ret = subdev_8255_init(dev, s, NULL,
- dev->iobase + thisboard->i8255_offset);
+ ret = subdev_8255_init(dev, s, NULL, thisboard->i8255_offset);
if (ret)
return ret;
} else {
diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h
index 18cc170facd0..f86167da5895 100644
--- a/drivers/staging/comedi/drivers/das08.h
+++ b/drivers/staging/comedi/drivers/das08.h
@@ -44,7 +44,6 @@ struct das08_private_struct {
* without separate do register
*/
const unsigned int *pg_gainlist;
- unsigned int ao_readback[2]; /* assume 2 AO channels */
};
int das08_common_attach(struct comedi_device *dev, unsigned long iobase);
diff --git a/drivers/staging/comedi/drivers/das08_isa.c b/drivers/staging/comedi/drivers/das08_isa.c
index 4fb03d3852d3..e4ba268e78ab 100644
--- a/drivers/staging/comedi/drivers/das08_isa.c
+++ b/drivers/staging/comedi/drivers/das08_isa.c
@@ -174,7 +174,7 @@ static const struct das08_board_struct das08_isa_boards[] = {
static int das08_isa_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- const struct das08_board_struct *thisboard = comedi_board(dev);
+ const struct das08_board_struct *thisboard = dev->board_ptr;
struct das08_private_struct *devpriv;
int ret;
diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/staging/comedi/drivers/das08_pci.c
index 4ce3eb0a64cc..0987ce554945 100644
--- a/drivers/staging/comedi/drivers/das08_pci.c
+++ b/drivers/staging/comedi/drivers/das08_pci.c
@@ -77,7 +77,7 @@ static struct comedi_driver das08_pci_comedi_driver = {
.driver_name = "pci-das08",
.module = THIS_MODULE,
.auto_attach = das08_pci_auto_attach,
- .detach = comedi_pci_disable,
+ .detach = comedi_pci_detach,
};
static int das08_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index 057bc16f8ddc..2d8e86cec47a 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -631,7 +631,7 @@ static int das16_ai_check_chanlist(struct comedi_device *dev,
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);
+ const struct das16_board *board = dev->board_ptr;
struct das16_private_struct *devpriv = dev->private;
int err = 0;
unsigned int trig_mask;
@@ -692,7 +692,9 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
board->ai_speed);
- if (cmd->stop_src == TRIG_NONE)
+ 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)
@@ -748,7 +750,7 @@ static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
{
- const struct das16_board *board = comedi_board(dev);
+ const struct das16_board *board = dev->board_ptr;
struct das16_private_struct *devpriv = dev->private;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
@@ -756,9 +758,9 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
unsigned long flags;
int range;
- if (cmd->flags & TRIG_RT) {
+ if (cmd->flags & CMDF_PRIORITY) {
dev_err(dev->class_dev,
- "isa dma transfers cannot be performed with TRIG_RT, aborting\n");
+ "isa dma transfers cannot be performed with CMDF_PRIORITY, aborting\n");
return -1;
}
@@ -883,7 +885,7 @@ static int das16_ai_insn_read(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- const struct das16_board *board = comedi_board(dev);
+ const struct das16_board *board = dev->board_ptr;
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int range = CR_RANGE(insn->chanspec);
unsigned int val;
@@ -927,11 +929,13 @@ static int das16_ao_insn_write(struct comedi_device *dev,
unsigned int *data)
{
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int val;
int i;
for (i = 0; i < insn->n; i++) {
- val = data[i];
+ unsigned int val = data[i];
+
+ s->readback[chan] = val;
+
val <<= 4;
outb(val & 0xff, dev->iobase + DAS16_AO_LSB_REG(chan));
@@ -966,7 +970,7 @@ static int das16_do_insn_bits(struct comedi_device *dev,
static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct das16_board *board = comedi_board(dev);
+ const struct das16_board *board = dev->board_ptr;
int diobits;
/* diobits indicates boards */
@@ -991,7 +995,7 @@ static void das16_reset(struct comedi_device *dev)
static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct das16_board *board = comedi_board(dev);
+ const struct das16_board *board = dev->board_ptr;
struct das16_private_struct *devpriv;
struct comedi_subdevice *s;
struct comedi_lrange *lrange;
@@ -1163,6 +1167,11 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->maxdata = 0x0fff;
s->range_table = devpriv->user_ao_range_table;
s->insn_write = das16_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -1191,8 +1200,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* 8255 Digital I/O subdevice */
if (board->has_8255) {
s = &dev->subdevices[4];
- ret = subdev_8255_init(dev, s, NULL,
- dev->iobase + board->i8255_offset);
+ ret = subdev_8255_init(dev, s, NULL, board->i8255_offset);
if (ret)
return ret;
}
@@ -1213,7 +1221,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
static void das16_detach(struct comedi_device *dev)
{
- const struct das16_board *board = comedi_board(dev);
+ const struct das16_board *board = dev->board_ptr;
struct das16_private_struct *devpriv = dev->private;
int i;
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index 5b6998b54060..24b63c452f51 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -218,12 +218,10 @@ static int das16m1_cmd_test(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_COUNT) {
- /* any count is allowed */
- } else {
- /* TRIG_NONE */
+ 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;
@@ -608,7 +606,7 @@ static int das16m1_attach(struct comedi_device *dev,
s = &dev->subdevices[3];
/* 8255 */
- ret = subdev_8255_init(dev, s, NULL, devpriv->extra_iobase);
+ ret = subdev_8255_init(dev, s, NULL, DAS16M1_82C55);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index 0cfca33965f6..a53d87ce9b14 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -453,7 +453,7 @@ static const struct comedi_lrange range_ao_2 = {
static inline uint16_t munge_bipolar_sample(const struct comedi_device *dev,
uint16_t sample)
{
- const struct das1800_board *thisboard = comedi_board(dev);
+ const struct das1800_board *thisboard = dev->board_ptr;
sample += 1 << (thisboard->resolution - 1);
return sample;
@@ -731,15 +731,15 @@ static unsigned int burst_convert_arg(unsigned int convert_arg, int flags)
convert_arg = 64000;
/* the conversion time must be an integral number of microseconds */
- switch (flags & TRIG_ROUND_MASK) {
- case TRIG_ROUND_NEAREST:
+ switch (flags & CMDF_ROUND_MASK) {
+ case CMDF_ROUND_NEAREST:
default:
micro_sec = (convert_arg + 500) / 1000;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
micro_sec = convert_arg / 1000;
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
micro_sec = (convert_arg - 1) / 1000 + 1;
break;
}
@@ -773,7 +773,7 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct das1800_board *thisboard = comedi_board(dev);
+ const struct das1800_board *thisboard = dev->board_ptr;
struct das1800_private *devpriv = dev->private;
int err = 0;
unsigned int arg;
@@ -1088,14 +1088,14 @@ static int das1800_ai_do_cmd(struct comedi_device *dev,
struct comedi_async *async = s->async;
const struct comedi_cmd *cmd = &async->cmd;
- /* disable dma on TRIG_WAKE_EOS, or TRIG_RT
+ /* disable dma on CMDF_WAKE_EOS, or CMDF_PRIORITY
* (because dma in handler is unsafe at hard real-time priority) */
- if (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT))
+ if (cmd->flags & (CMDF_WAKE_EOS | CMDF_PRIORITY))
devpriv->irq_dma_bits &= ~DMA_ENABLED;
else
devpriv->irq_dma_bits |= devpriv->dma_bits;
- /* interrupt on end of conversion for TRIG_WAKE_EOS */
- if (cmd->flags & TRIG_WAKE_EOS) {
+ /* interrupt on end of conversion for CMDF_WAKE_EOS */
+ if (cmd->flags & CMDF_WAKE_EOS) {
/* interrupt fifo not empty */
devpriv->irq_dma_bits &= ~FIMD;
} else {
@@ -1136,7 +1136,7 @@ static int das1800_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- const struct das1800_board *thisboard = comedi_board(dev);
+ const struct das1800_board *thisboard = dev->board_ptr;
int i, n;
int chan, range, aref, chan_range;
int timeout = 1000;
@@ -1200,7 +1200,7 @@ static int das1800_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- const struct das1800_board *thisboard = comedi_board(dev);
+ const struct das1800_board *thisboard = dev->board_ptr;
struct das1800_private *devpriv = dev->private;
int chan = CR_CHAN(insn->chanspec);
/* int range = CR_RANGE(insn->chanspec); */
@@ -1329,7 +1329,7 @@ static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
static int das1800_probe(struct comedi_device *dev)
{
- const struct das1800_board *board = comedi_board(dev);
+ const struct das1800_board *board = dev->board_ptr;
int index;
int id;
@@ -1412,7 +1412,7 @@ static int das1800_attach(struct comedi_device *dev,
}
dev->board_ptr = das1800_boards + board;
- thisboard = comedi_board(dev);
+ thisboard = dev->board_ptr;
dev->board_name = thisboard->name;
/* if it is an 'ao' board with fancy analog out then we need extra io ports */
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index d18eea6c01aa..ab6e40608885 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -143,7 +143,6 @@ struct das6402_private {
unsigned int divider2;
unsigned int ao_range;
- unsigned int ao_readback[2];
};
static void das6402_set_mode(struct comedi_device *dev,
@@ -328,7 +327,7 @@ static int das6402_ao_insn_write(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
val = data[i];
- devpriv->ao_readback[chan] = val;
+ s->readback[chan] = val;
if (s->maxdata == 0x0fff) {
/*
@@ -358,9 +357,7 @@ static int das6402_ao_insn_read(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- struct das6402_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
- int i;
/*
* If XFER mode is enabled, reading any DAC register
@@ -368,10 +365,7 @@ static int das6402_ao_insn_read(struct comedi_device *dev,
*/
inw(dev->iobase + DAS6402_AO_LSB_REG(chan));
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return insn->n;
+ return comedi_readback_insn_read(dev, s, insn, data);
}
static int das6402_di_insn_bits(struct comedi_device *dev,
@@ -440,7 +434,7 @@ static void das6402_reset(struct comedi_device *dev)
static int das6402_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- const struct das6402_boardinfo *board = comedi_board(dev);
+ const struct das6402_boardinfo *board = dev->board_ptr;
struct das6402_private *devpriv;
struct comedi_subdevice *s;
int ret;
@@ -510,6 +504,10 @@ static int das6402_attach(struct comedi_device *dev,
s->insn_write = das6402_ao_insn_write;
s->insn_read = das6402_ao_insn_read;
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
+
/* Digital Input subdevice */
s = &dev->subdevices[2];
s->type = COMEDI_SUBD_DI;
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index cbbb29797b83..d75e5528258c 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -248,7 +248,7 @@ static unsigned das800_ind_read(struct comedi_device *dev, unsigned reg)
static void das800_enable(struct comedi_device *dev)
{
- const struct das800_board *thisboard = comedi_board(dev);
+ const struct das800_board *thisboard = dev->board_ptr;
struct das800_private *devpriv = dev->private;
unsigned long irq_flags;
@@ -325,7 +325,7 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct das800_board *thisboard = comedi_board(dev);
+ const struct das800_board *thisboard = dev->board_ptr;
struct das800_private *devpriv = dev->private;
int err = 0;
unsigned int arg;
@@ -398,7 +398,7 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev,
static int das800_ai_do_cmd(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- const struct das800_board *thisboard = comedi_board(dev);
+ const struct das800_board *thisboard = dev->board_ptr;
struct das800_private *devpriv = dev->private;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
@@ -633,7 +633,7 @@ static int das800_do_insn_bits(struct comedi_device *dev,
static int das800_probe(struct comedi_device *dev)
{
- const struct das800_board *thisboard = comedi_board(dev);
+ const struct das800_board *thisboard = dev->board_ptr;
int board = thisboard ? thisboard - das800_boards : -EINVAL;
int id_bits;
unsigned long irq_flags;
@@ -695,7 +695,7 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -ENODEV;
}
dev->board_ptr = das800_boards + board;
- thisboard = comedi_board(dev);
+ thisboard = dev->board_ptr;
dev->board_name = thisboard->name;
if (irq > 1 && irq <= 7) {
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index e9cd2517ad81..7215e09305cf 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -47,9 +47,10 @@ Configuration Options:
#define DMM32AT_AILOW 0x02
#define DMM32AT_AIHIGH 0x03
-#define DMM32AT_DACLSB 0x04
#define DMM32AT_DACSTAT 0x04
-#define DMM32AT_DACMSB 0x05
+#define DMM32AT_DACLSB_REG 0x04
+#define DMM32AT_DACMSB_REG 0x05
+#define DMM32AT_DACMSB_CHAN(x) ((x) << 6)
#define DMM32AT_FIFOCNTRL 0x07
#define DMM32AT_FIFOSTAT 0x07
@@ -150,15 +151,10 @@ static const struct comedi_lrange dmm32at_aoranges = {
};
struct dmm32at_private {
-
int data;
int ai_inuse;
unsigned int ai_scans_left;
-
- /* Used for AO readback */
- unsigned int ao_readback[4];
unsigned char dio_config;
-
};
static int dmm32at_ai_status(struct comedi_device *dev,
@@ -540,56 +536,35 @@ static int dmm32at_ao_eoc(struct comedi_device *dev,
return -EBUSY;
}
-static int dmm32at_ao_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int dmm32at_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct dmm32at_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
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. */
for (i = 0; i < insn->n; i++) {
+ unsigned int val = data[i];
+ int ret;
- devpriv->ao_readback[chan] = data[i];
-
- /* get the low byte */
- lo = data[i] & 0x00ff;
- /* high byte also contains channel number */
- hi = (data[i] >> 8) + chan * (1 << 6);
- /* write the low and high values to the board */
- outb(lo, dev->iobase + DMM32AT_DACLSB);
- outb(hi, dev->iobase + DMM32AT_DACMSB);
+ /* write LSB then MSB + chan to load DAC */
+ outb(val & 0xff, dev->iobase + DMM32AT_DACLSB_REG);
+ outb((val >> 8) | DMM32AT_DACMSB_CHAN(chan),
+ dev->iobase + DMM32AT_DACMSB_REG);
/* wait for circuit to settle */
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);
+ /* dummy read to update DAC */
+ inb(dev->iobase + DMM32AT_DACMSB_REG);
+ s->readback[chan] = val;
}
- /* return the number of samples read/written */
- return i;
-}
-
-static int dmm32at_ao_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct dmm32at_private *devpriv = dev->private;
- int i;
- int chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return i;
+ return insn->n;
}
static int dmm32at_dio_insn_bits(struct comedi_device *dev,
@@ -764,8 +739,12 @@ static int dmm32at_attach(struct comedi_device *dev,
s->n_chan = 4;
s->maxdata = 0x0fff;
s->range_table = &dmm32at_aoranges;
- s->insn_write = dmm32at_ao_winsn;
- s->insn_read = dmm32at_ao_rinsn;
+ s->insn_write = dmm32at_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[2];
/* digital i/o subdevice */
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index ad8ba0be4878..e97386343a0e 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -207,9 +207,7 @@ static const struct dt2801_board boardtypes[] = {
};
struct dt2801_private {
-
const struct comedi_lrange *dac_range_types[2];
- unsigned int ao_readback[2];
};
/* These are the low-level routines:
@@ -309,7 +307,7 @@ static int dt2801_wait_for_ready(struct comedi_device *dev)
return -ETIME;
}
-static int dt2801_writecmd(struct comedi_device *dev, int command)
+static void dt2801_writecmd(struct comedi_device *dev, int command)
{
int stat;
@@ -323,8 +321,6 @@ static int dt2801_writecmd(struct comedi_device *dev, int command)
if (!(stat & DT_S_READY))
dev_dbg(dev->class_dev, "!ready in %s, ignoring\n", __func__);
outb_p(command, dev->iobase + DT2801_CMD);
-
- return 0;
}
static int dt2801_reset(struct comedi_device *dev)
@@ -380,7 +376,7 @@ static int probe_number_of_ai_chans(struct comedi_device *dev)
int data;
for (n_chans = 0; n_chans < 16; n_chans++) {
- stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
+ dt2801_writecmd(dev, DT_C_READ_ADIM);
dt2801_writedata(dev, 0);
dt2801_writedata(dev, n_chans);
stat = dt2801_readdata2(dev, &data);
@@ -451,7 +447,7 @@ static int dt2801_ai_insn_read(struct comedi_device *dev,
int i;
for (i = 0; i < insn->n; i++) {
- stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
+ dt2801_writecmd(dev, DT_C_READ_ADIM);
dt2801_writedata(dev, CR_RANGE(insn->chanspec));
dt2801_writedata(dev, CR_CHAN(insn->chanspec));
stat = dt2801_readdata2(dev, &d);
@@ -465,28 +461,18 @@ static int dt2801_ai_insn_read(struct comedi_device *dev,
return i;
}
-static int dt2801_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct dt2801_private *devpriv = dev->private;
-
- data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
-
- return 1;
-}
-
static int dt2801_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 dt2801_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
dt2801_writecmd(dev, DT_C_WRITE_DAIM);
- dt2801_writedata(dev, CR_CHAN(insn->chanspec));
+ dt2801_writedata(dev, chan);
dt2801_writedata2(dev, data[0]);
- devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0];
+ s->readback[chan] = data[0];
return 1;
}
@@ -571,7 +557,7 @@ static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it)
havetype:
dev->board_ptr = boardtypes + type;
- board = comedi_board(dev);
+ board = dev->board_ptr;
n_ai_chans = probe_number_of_ai_chans(dev);
@@ -610,8 +596,12 @@ havetype:
s->range_table_list = devpriv->dac_range_types;
devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]);
devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]);
- s->insn_read = dt2801_ao_insn_read;
s->insn_write = dt2801_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[2];
/* 1st digital subdevice */
diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c
index a2e9caf3256f..1736e397ad2c 100644
--- a/drivers/staging/comedi/drivers/dt2811.c
+++ b/drivers/staging/comedi/drivers/dt2811.c
@@ -213,7 +213,6 @@ struct dt2811_private {
dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5
} dac_range[2];
const struct comedi_lrange *range_type_list[2];
- unsigned int ao_readback[2];
};
static const struct comedi_lrange *dac_range_types[] = {
@@ -257,39 +256,24 @@ static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
return i;
}
-static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int dt2811_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct dt2811_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = s->readback[chan];
int i;
- int chan;
-
- chan = CR_CHAN(insn->chanspec);
for (i = 0; i < insn->n; i++) {
- outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
- outb((data[i] >> 8) & 0xff,
+ val = data[i];
+ outb(val & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
+ outb((val >> 8) & 0xff,
dev->iobase + DT2811_DADAT0HI + 2 * chan);
- devpriv->ao_readback[chan] = data[i];
}
+ s->readback[chan] = val;
- return i;
-}
-
-static int dt2811_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct dt2811_private *devpriv = dev->private;
- int i;
- int chan;
-
- chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return i;
+ return insn->n;
}
static int dt2811_di_insn_bits(struct comedi_device *dev,
@@ -337,7 +321,7 @@ static int dt2811_do_insn_bits(struct comedi_device *dev,
static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
/* int i; */
- const struct dt2811_board *board = comedi_board(dev);
+ const struct dt2811_board *board = dev->board_ptr;
struct dt2811_private *devpriv;
int ret;
struct comedi_subdevice *s;
@@ -429,12 +413,16 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE;
s->n_chan = 2;
- s->insn_write = dt2811_ao_insn;
- s->insn_read = dt2811_ao_insn_read;
s->maxdata = 0xfff;
s->range_table_list = devpriv->range_type_list;
devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]];
devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]];
+ s->insn_write = dt2811_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[2];
/* di subdevice */
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 5de26745783a..cc974a5e5cf6 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -315,8 +315,6 @@ struct dt282x_private {
unsigned int divisor;
- unsigned short ao_readback[2];
-
int dacsr; /* software copies of registers */
int adcsr;
int supcsr;
@@ -405,15 +403,15 @@ static unsigned int dt282x_ns_to_timer(unsigned int *ns, unsigned int flags)
if (prescale == 1)
continue;
base = 250 * (1 << prescale);
- switch (flags & TRIG_ROUND_MASK) {
- case TRIG_ROUND_NEAREST:
+ switch (flags & CMDF_ROUND_MASK) {
+ case CMDF_ROUND_NEAREST:
default:
divider = (*ns + base / 2) / base;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
divider = (*ns) / base;
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
divider = (*ns + base - 1) / base;
break;
}
@@ -683,7 +681,7 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct dt282x_board *board = comedi_board(dev);
+ const struct dt282x_board *board = dev->board_ptr;
struct dt282x_private *devpriv = dev->private;
int err = 0;
unsigned int arg;
@@ -730,11 +728,10 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_COUNT) {
- /* any count is allowed */
- } else { /* TRIG_NONE */
+ if (cmd->stop_src == TRIG_COUNT)
+ err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
+ else /* TRIG_EXT | TRIG_NONE */
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
- }
if (err)
return 3;
@@ -826,21 +823,6 @@ static int dt282x_ai_cancel(struct comedi_device *dev,
return 0;
}
-static int dt282x_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct dt282x_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 dt282x_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -849,14 +831,14 @@ static int dt282x_ao_insn_write(struct comedi_device *dev,
struct dt282x_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int range = CR_RANGE(insn->chanspec);
- unsigned int val;
int i;
devpriv->dacsr |= DT2821_DACSR_SSEL | DT2821_DACSR_YSEL(chan);
for (i = 0; i < insn->n; i++) {
- val = data[i];
- devpriv->ao_readback[chan] = val;
+ unsigned int val = data[i];
+
+ s->readback[chan] = val;
if (comedi_range_is_bipolar(s, range))
val = comedi_offset_munge(s, val);
@@ -907,11 +889,10 @@ static int dt282x_ao_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_COUNT) {
- /* any count is allowed */
- } else { /* TRIG_NONE */
+ if (cmd->stop_src == TRIG_COUNT)
+ err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
+ else /* TRIG_EXT | TRIG_NONE */
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
- }
if (err)
return 3;
@@ -1166,7 +1147,7 @@ static int dt282x_initialize(struct comedi_device *dev)
*/
static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct dt282x_board *board = comedi_board(dev);
+ const struct dt282x_board *board = dev->board_ptr;
struct dt282x_private *devpriv;
struct comedi_subdevice *s;
int ret;
@@ -1252,12 +1233,10 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->subdev_flags = SDF_WRITABLE;
s->n_chan = board->dachan;
s->maxdata = board->ao_maxdata;
-
/* ranges are per-channel, set by jumpers on the board */
s->range_table = &dt282x_ao_range;
-
- s->insn_read = dt282x_ao_insn_read;
s->insn_write = dt282x_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
if (dev->irq) {
dev->write_subdev = s;
s->subdev_flags |= SDF_CMD_WRITE;
@@ -1266,6 +1245,10 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->do_cmd = dt282x_ao_cmd;
s->cancel = dt282x_ao_cancel;
}
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index 56e21cc2dcfe..825561046b6f 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -245,7 +245,6 @@ static const struct dt3k_boardtype dt3k_boardtypes[] = {
struct dt3k_private {
unsigned int lock;
- unsigned int ao_readback[2];
unsigned int ai_front;
unsigned int ai_rear;
};
@@ -378,15 +377,15 @@ static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
for (prescale = 0; prescale < 16; prescale++) {
base = timer_base * (prescale + 1);
- switch (flags & TRIG_ROUND_MASK) {
- case TRIG_ROUND_NEAREST:
+ switch (flags & CMDF_ROUND_MASK) {
+ case CMDF_ROUND_NEAREST:
default:
divider = (*nanosec + base / 2) / base;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
divider = (*nanosec) / base;
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
divider = (*nanosec) / base;
break;
}
@@ -406,7 +405,7 @@ static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
static int dt3k_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
- const struct dt3k_boardtype *this_board = comedi_board(dev);
+ const struct dt3k_boardtype *this_board = dev->board_ptr;
int err = 0;
unsigned int arg;
@@ -424,9 +423,6 @@ static int dt3k_ai_cmdtest(struct comedi_device *dev,
/* Step 2a : make sure trigger sources are unique */
/* 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);
@@ -488,7 +484,6 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
unsigned int chan, range, aref;
unsigned int divider;
unsigned int tscandiv;
- unsigned int mode;
for (i = 0; i < cmd->chanlist_len; i++) {
chan = CR_CHAN(cmd->chanlist[i]);
@@ -513,8 +508,7 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
writew((tscandiv & 0xffff), dev->mmio + DPR_Params(4));
}
- mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
- writew(mode, dev->mmio + DPR_Params(5));
+ writew(DT3000_AD_RETRIG_INTERNAL, dev->mmio + DPR_Params(5));
writew(aref == AREF_DIFF, dev->mmio + DPR_Params(6));
writew(AI_FIFO_DEPTH / 2, dev->mmio + DPR_Params(7));
@@ -550,35 +544,22 @@ static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
return i;
}
-static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int dt3k_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct dt3k_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = s->readback[chan];
int i;
- unsigned int chan;
- chan = CR_CHAN(insn->chanspec);
for (i = 0; i < insn->n; i++) {
- dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
- devpriv->ao_readback[chan] = data[i];
+ val = data[i];
+ dt3k_writesingle(dev, SUBS_AO, chan, val);
}
+ s->readback[chan] = val;
- return i;
-}
-
-static int dt3k_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct dt3k_private *devpriv = dev->private;
- int i;
- unsigned int chan;
-
- chan = CR_CHAN(insn->chanspec);
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return i;
+ return insn->n;
}
static void dt3k_dio_config(struct comedi_device *dev, int bits)
@@ -714,11 +695,15 @@ static int dt3000_auto_attach(struct comedi_device *dev,
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE;
s->n_chan = 2;
- s->insn_read = dt3k_ao_insn_read;
- s->insn_write = dt3k_ao_insn;
s->maxdata = (1 << this_board->dabits) - 1;
s->len_chanlist = 1;
s->range_table = &range_bipolar10;
+ s->insn_write = dt3k_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[2];
/* dio subsystem */
@@ -750,20 +735,11 @@ static int dt3000_auto_attach(struct comedi_device *dev,
return 0;
}
-static void dt3000_detach(struct comedi_device *dev)
-{
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->mmio)
- iounmap(dev->mmio);
- comedi_pci_disable(dev);
-}
-
static struct comedi_driver dt3000_driver = {
.driver_name = "dt3000",
.module = THIS_MODULE,
.auto_attach = dt3000_auto_attach,
- .detach = dt3000_detach,
+ .detach = comedi_pci_detach,
};
static int dt3000_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index bd2ca2b371e6..77bb89fee327 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -240,7 +240,6 @@ struct dt9812_private {
size_t size;
} cmd_wr, cmd_rd;
u16 device;
- u16 ao_shadow[2];
};
static int dt9812_read_info(struct comedi_device *dev,
@@ -546,7 +545,6 @@ static int dt9812_analog_out(struct comedi_device *dev, int channel, u16 value)
break;
}
ret = dt9812_rmw_multiple_registers(dev, 3, rmw);
- devpriv->ao_shadow[channel] = value;
up(&devpriv->sem);
@@ -609,15 +607,13 @@ static int dt9812_ao_insn_read(struct comedi_device *dev,
unsigned int *data)
{
struct dt9812_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int i;
+ int ret;
down(&devpriv->sem);
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_shadow[chan];
+ ret = comedi_readback_insn_read(dev, s, insn, data);
up(&devpriv->sem);
- return insn->n;
+ return ret;
}
static int dt9812_ao_insn_write(struct comedi_device *dev,
@@ -626,13 +622,17 @@ static int dt9812_ao_insn_write(struct comedi_device *dev,
unsigned int *data)
{
unsigned int chan = CR_CHAN(insn->chanspec);
- int ret;
int i;
for (i = 0; i < insn->n; i++) {
- ret = dt9812_analog_out(dev, chan, data[i]);
+ unsigned int val = data[i];
+ int ret;
+
+ ret = dt9812_analog_out(dev, chan, val);
if (ret)
return ret;
+
+ s->readback[chan] = val;
}
return insn->n;
@@ -769,6 +769,7 @@ static int dt9812_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
bool is_unipolar;
int ret;
+ int i;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
@@ -828,8 +829,12 @@ static int dt9812_auto_attach(struct comedi_device *dev,
s->insn_write = dt9812_ao_insn_write;
s->insn_read = dt9812_ao_insn_read;
- devpriv->ao_shadow[0] = is_unipolar ? 0x0000 : 0x0800;
- devpriv->ao_shadow[1] = is_unipolar ? 0x0000 : 0x0800;
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < s->n_chan; i++)
+ s->readback[i] = is_unipolar ? 0x0000 : 0x0800;
return 0;
}
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index e5593f8c7406..608aee0c3a15 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -243,9 +243,9 @@ static void dyna_pci10xx_detach(struct comedi_device *dev)
{
struct dyna_pci10xx_private *devpriv = dev->private;
+ comedi_pci_detach(dev);
if (devpriv)
mutex_destroy(&devpriv->mutex);
- comedi_pci_disable(dev);
}
static struct comedi_driver dyna_pci10xx_driver = {
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index 4e410f3b0e24..5a1e3c8fc01c 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -44,10 +44,6 @@
#define FL512_AO_DATA_REG(x) (0x04 + ((x) * 2))
#define FL512_AO_TRIG_REG(x) (0x04 + ((x) * 2))
-struct fl512_private {
- unsigned short ao_readback[2];
-};
-
static const struct comedi_lrange range_fl512 = {
4, {
BIP_RANGE(0.5),
@@ -92,9 +88,8 @@ static int fl512_ao_insn_write(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- struct fl512_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int val = devpriv->ao_readback[chan];
+ unsigned int val = s->readback[chan];
int i;
for (i = 0; i < insn->n; i++) {
@@ -105,29 +100,13 @@ static int fl512_ao_insn_write(struct comedi_device *dev,
outb((val >> 8) & 0xf, dev->iobase + FL512_AO_DATA_REG(chan));
inb(dev->iobase + FL512_AO_TRIG_REG(chan));
}
- devpriv->ao_readback[chan] = val;
-
- return insn->n;
-}
-
-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;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int i;
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
+ s->readback[chan] = val;
return insn->n;
}
static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- struct fl512_private *devpriv;
struct comedi_subdevice *s;
int ret;
@@ -135,10 +114,6 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
ret = comedi_alloc_subdevices(dev, 2);
if (ret)
return ret;
@@ -160,7 +135,11 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->maxdata = 0x0fff;
s->range_table = &range_fl512;
s->insn_write = fl512_ao_insn_write;
- s->insn_read = fl512_ao_insn_read;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
return 0;
}
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index 91c1e8cf5d24..b8975a4606ea 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -422,12 +422,10 @@ static int gsc_hpdi_cmd_test(struct comedi_device *dev,
if (err)
return 3;
- /* step 4: fix up any arguments */
-
- if (err)
- return 4;
+ /* Step 4: fix up any arguments */
/* Step 5: check channel list if it exists */
+
if (cmd->chanlist && cmd->chanlist_len > 0)
err |= gsc_hpdi_check_chanlist(dev, s, cmd);
@@ -507,6 +505,32 @@ static int gsc_hpdi_dio_insn_config(struct comedi_device *dev,
return insn->n;
}
+static void gsc_hpdi_free_dma(struct comedi_device *dev)
+{
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct hpdi_private *devpriv = dev->private;
+ int i;
+
+ if (!devpriv)
+ return;
+
+ /* free pci dma buffers */
+ for (i = 0; i < NUM_DMA_BUFFERS; i++) {
+ if (devpriv->dio_buffer[i])
+ pci_free_consistent(pcidev,
+ DMA_BUFFER_SIZE,
+ devpriv->dio_buffer[i],
+ devpriv->dio_buffer_phys_addr[i]);
+ }
+ /* free dma descriptors */
+ if (devpriv->dma_desc)
+ pci_free_consistent(pcidev,
+ sizeof(struct plx_dma_desc) *
+ NUM_DMA_DESCRIPTORS,
+ devpriv->dma_desc,
+ devpriv->dma_desc_phys_addr);
+}
+
static int gsc_hpdi_init(struct comedi_device *dev)
{
struct hpdi_private *devpriv = dev->private;
@@ -681,9 +705,7 @@ static int gsc_hpdi_auto_attach(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;
- unsigned int i;
if (dev->irq)
free_irq(dev->irq, dev);
@@ -694,24 +716,9 @@ static void gsc_hpdi_detach(struct comedi_device *dev)
}
if (dev->mmio)
iounmap(dev->mmio);
- /* free pci dma buffers */
- for (i = 0; i < NUM_DMA_BUFFERS; i++) {
- if (devpriv->dio_buffer[i])
- pci_free_consistent(pcidev,
- DMA_BUFFER_SIZE,
- devpriv->dio_buffer[i],
- devpriv->
- dio_buffer_phys_addr[i]);
- }
- /* free dma descriptors */
- if (devpriv->dma_desc)
- pci_free_consistent(pcidev,
- sizeof(struct plx_dma_desc) *
- NUM_DMA_DESCRIPTORS,
- devpriv->dma_desc,
- devpriv->dma_desc_phys_addr);
}
comedi_pci_disable(dev);
+ gsc_hpdi_free_dma(dev);
}
static struct comedi_driver gsc_hpdi_driver = {
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c
index a98cef2106a9..f4e1c1cf4178 100644
--- a/drivers/staging/comedi/drivers/icp_multi.c
+++ b/drivers/staging/comedi/drivers/icp_multi.c
@@ -107,7 +107,6 @@ static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 };
*/
struct icp_multi_private {
- char valid; /* card is usable */
unsigned int AdcCmdStatus; /* ADC Command/Status register */
unsigned int DacCmdStatus; /* DAC Command/Status register */
unsigned int IntEnable; /* Interrupt Enable register */
@@ -116,7 +115,6 @@ struct icp_multi_private {
unsigned char act_chanlist_len; /* len of scanlist */
unsigned char act_chanlist_pos; /* actual position in MUX list */
unsigned int *ai_chanlist; /* actaul chanlist */
- unsigned short ao_data[4]; /* data output buffer */
unsigned int do_data; /* Remember digital output data */
};
@@ -240,14 +238,15 @@ static int icp_multi_ao_eoc(struct comedi_device *dev,
return -EBUSY;
}
-static int icp_multi_insn_write_ao(struct comedi_device *dev,
+static int icp_multi_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
struct icp_multi_private *devpriv = dev->private;
- int n, chan, range;
- int ret;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ int i;
/* Disable D/A conversion ready interrupt */
devpriv->IntEnable &= ~DAC_READY;
@@ -257,10 +256,6 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev,
devpriv->IntStatus |= DAC_READY;
writew(devpriv->IntStatus, dev->mmio + ICP_MULTI_INT_STAT);
- /* Get channel number and range */
- chan = CR_CHAN(insn->chanspec);
- range = CR_RANGE(insn->chanspec);
-
/* Set up range and channel data */
/* Bit 4 = 1 : Bipolar */
/* Bit 5 = 0 : 5V */
@@ -272,7 +267,10 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev,
writew(devpriv->DacCmdStatus, dev->mmio + ICP_MULTI_DAC_CSR);
- for (n = 0; n < insn->n; n++) {
+ for (i = 0; i < insn->n; i++) {
+ unsigned int val = data[i];
+ int ret;
+
/* Wait for analogue output data register to be
* ready for new data, or get fed up waiting */
ret = comedi_timeout(dev, s, insn, icp_multi_ao_eoc, 0);
@@ -287,42 +285,20 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev,
writew(devpriv->IntStatus,
dev->mmio + ICP_MULTI_INT_STAT);
- /* Clear data received */
- devpriv->ao_data[chan] = 0;
-
return ret;
}
- /* Write data to analogue output data register */
- writew(data[n], dev->mmio + ICP_MULTI_AO);
+ writew(val, dev->mmio + ICP_MULTI_AO);
/* Set DAC_ST bit to write the data to selected channel */
devpriv->DacCmdStatus |= DAC_ST;
writew(devpriv->DacCmdStatus, dev->mmio + ICP_MULTI_DAC_CSR);
devpriv->DacCmdStatus &= ~DAC_ST;
- /* Save analogue output data */
- devpriv->ao_data[chan] = data[n];
+ s->readback[chan] = val;
}
- return n;
-}
-
-static int icp_multi_insn_read_ao(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct icp_multi_private *devpriv = dev->private;
- int n, chan;
-
- /* Get channel number */
- chan = CR_CHAN(insn->chanspec);
-
- /* Read analogue outputs */
- for (n = 0; n < insn->n; n++)
- data[n] = devpriv->ao_data[chan];
-
- return n;
+ return insn->n;
}
static int icp_multi_insn_bits_di(struct comedi_device *dev,
@@ -518,8 +494,12 @@ static int icp_multi_auto_attach(struct comedi_device *dev,
s->maxdata = 0x0fff;
s->len_chanlist = 4;
s->range_table = &range_analog;
- s->insn_write = icp_multi_insn_write_ao;
- s->insn_read = icp_multi_insn_read_ao;
+ s->insn_write = icp_multi_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[2];
s->type = COMEDI_SUBD_DI;
@@ -549,23 +529,14 @@ static int icp_multi_auto_attach(struct comedi_device *dev,
s->insn_read = icp_multi_insn_read_ctr;
s->insn_write = icp_multi_insn_write_ctr;
- devpriv->valid = 1;
-
return 0;
}
static void icp_multi_detach(struct comedi_device *dev)
{
- struct icp_multi_private *devpriv = dev->private;
-
- if (devpriv)
- if (devpriv->valid)
- icp_multi_reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
if (dev->mmio)
- iounmap(dev->mmio);
- comedi_pci_disable(dev);
+ icp_multi_reset(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver icp_multi_driver = {
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index 687db433e131..cc5fd75b8bc0 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -132,44 +132,25 @@ static const struct comedi_lrange ii20k_ai_ranges = {
},
};
-struct ii20k_ao_private {
- unsigned int last_data[2];
-};
-
static void __iomem *ii20k_module_iobase(struct comedi_device *dev,
struct comedi_subdevice *s)
{
return dev->mmio + (s->index + 1) * II20K_MOD_OFFSET;
}
-static int ii20k_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct ii20k_ao_private *ao_spriv = s->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int i;
-
- for (i = 0; i < insn->n; i++)
- data[i] = ao_spriv->last_data[chan];
-
- return insn->n;
-}
-
static int ii20k_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
- struct ii20k_ao_private *ao_spriv = s->private;
void __iomem *iobase = ii20k_module_iobase(dev, s);
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int val = ao_spriv->last_data[chan];
int i;
for (i = 0; i < insn->n; i++) {
- val = data[i];
+ unsigned int val = data[i];
+
+ s->readback[chan] = val;
/* munge data */
val += ((s->maxdata + 1) >> 1);
@@ -180,8 +161,6 @@ static int ii20k_ao_insn_write(struct comedi_device *dev,
writeb(0x00, iobase + II20K_AO_STRB_REG(chan));
}
- ao_spriv->last_data[chan] = val;
-
return insn->n;
}
@@ -398,26 +377,26 @@ static int ii20k_dio_insn_bits(struct comedi_device *dev,
static int ii20k_init_module(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- struct ii20k_ao_private *ao_spriv;
void __iomem *iobase = ii20k_module_iobase(dev, s);
unsigned char id;
+ int ret;
id = readb(iobase + II20K_ID_REG);
switch (id) {
case II20K_ID_PCI20006M_1:
case II20K_ID_PCI20006M_2:
- ao_spriv = comedi_alloc_spriv(s, sizeof(*ao_spriv));
- if (!ao_spriv)
- return -ENOMEM;
-
/* Analog Output subdevice */
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE;
s->n_chan = (id == II20K_ID_PCI20006M_2) ? 2 : 1;
s->maxdata = 0xffff;
s->range_table = &ii20k_ao_ranges;
- s->insn_read = ii20k_ao_insn_read;
s->insn_write = ii20k_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
break;
case II20K_ID_PCI20341M_1:
/* Analog Input subdevice */
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 7b20e19ecbf7..81fab2dfafa4 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -681,7 +681,7 @@ static int jr3_pci_auto_attach(struct comedi_device *dev,
unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- static const struct jr3_pci_board *board = NULL;
+ static const struct jr3_pci_board *board;
struct jr3_pci_dev_private *devpriv;
struct jr3_pci_subdev_private *spriv;
struct comedi_subdevice *s;
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index f46722c2648f..77e94a34b51e 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -212,7 +212,7 @@ static struct comedi_driver ke_counter_driver = {
.driver_name = "ke_counter",
.module = THIS_MODULE,
.auto_attach = ke_counter_auto_attach,
- .detach = comedi_pci_disable,
+ .detach = comedi_pci_detach,
};
static int ke_counter_pci_probe(struct pci_dev *dev,
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index 9a5c535451a1..6561b00bea59 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -176,8 +176,6 @@ broken.
struct me4000_info {
unsigned long plx_regbase;
unsigned long timer_regbase;
-
- unsigned int ao_readback[4];
};
enum me4000_boardid {
@@ -473,7 +471,7 @@ static int me4000_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *subdevice,
struct comedi_insn *insn, unsigned int *data)
{
- const struct me4000_board *thisboard = comedi_board(dev);
+ const struct me4000_board *thisboard = dev->board_ptr;
int chan = CR_CHAN(insn->chanspec);
int rang = CR_RANGE(insn->chanspec);
int aref = CR_AREF(insn->chanspec);
@@ -601,7 +599,7 @@ static int me4000_ai_check_chanlist(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct me4000_board *board = comedi_board(dev);
+ const struct me4000_board *board = dev->board_ptr;
unsigned int max_diff_chan = board->ai_diff_nchan;
unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
int i;
@@ -617,7 +615,7 @@ static int me4000_ai_check_chanlist(struct comedi_device *dev,
return -EINVAL;
}
- if (aref == SDF_DIFF) {
+ if (aref == AREF_DIFF) {
if (chan >= max_diff_chan) {
dev_dbg(dev->class_dev,
"Channel number to high\n");
@@ -652,10 +650,10 @@ static int ai_round_cmd_args(struct comedi_device *dev,
*init_ticks = (cmd->start_arg * 33) / 1000;
rest = (cmd->start_arg * 33) % 1000;
- if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) {
+ if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) {
if (rest > 33)
(*init_ticks)++;
- } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) {
+ } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) {
if (rest)
(*init_ticks)++;
}
@@ -665,10 +663,10 @@ static int ai_round_cmd_args(struct comedi_device *dev,
*scan_ticks = (cmd->scan_begin_arg * 33) / 1000;
rest = (cmd->scan_begin_arg * 33) % 1000;
- if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) {
+ if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) {
if (rest > 33)
(*scan_ticks)++;
- } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) {
+ } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) {
if (rest)
(*scan_ticks)++;
}
@@ -678,10 +676,10 @@ static int ai_round_cmd_args(struct comedi_device *dev,
*chan_ticks = (cmd->convert_arg * 33) / 1000;
rest = (cmd->convert_arg * 33) % 1000;
- if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) {
+ if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) {
if (rest > 33)
(*chan_ticks)++;
- } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) {
+ } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) {
if (rest)
(*chan_ticks)++;
}
@@ -731,7 +729,7 @@ static int ai_write_chanlist(struct comedi_device *dev,
else
entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10;
- if (aref == SDF_DIFF)
+ if (aref == AREF_DIFF)
entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL;
else
entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED;
@@ -851,7 +849,7 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
int err = 0;
/* Only rounding flags are implemented */
- cmd->flags &= TRIG_ROUND_NEAREST | TRIG_ROUND_UP | TRIG_ROUND_DOWN;
+ cmd->flags &= CMDF_ROUND_NEAREST | CMDF_ROUND_UP | CMDF_ROUND_DOWN;
/* Round the timer arguments */
ai_round_cmd_args(dev, s, cmd, &init_ticks, &scan_ticks, &chan_ticks);
@@ -925,6 +923,11 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
err |= -EINVAL;
}
+ 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;
@@ -1031,13 +1034,6 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev,
err++;
}
}
- if (cmd->stop_src == TRIG_COUNT) {
- if (cmd->stop_arg == 0) {
- dev_err(dev->class_dev, "Invalid stop arg\n");
- cmd->stop_arg = 1;
- err++;
- }
- }
if (cmd->scan_end_src == TRIG_COUNT) {
if (cmd->scan_end_arg == 0) {
dev_err(dev->class_dev, "Invalid scan end arg\n");
@@ -1188,44 +1184,14 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-/*=============================================================================
- Analog output section
- ===========================================================================*/
-
static int me4000_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)
{
- const struct me4000_board *thisboard = comedi_board(dev);
- struct me4000_info *info = dev->private;
int chan = CR_CHAN(insn->chanspec);
- int rang = CR_RANGE(insn->chanspec);
- int aref = CR_AREF(insn->chanspec);
unsigned int tmp;
- if (insn->n == 0) {
- return 0;
- } else if (insn->n > 1) {
- dev_err(dev->class_dev, "Invalid instruction length %d\n",
- insn->n);
- return -EINVAL;
- }
-
- if (chan >= thisboard->ao_nchan) {
- dev_err(dev->class_dev, "Invalid channel %d\n", insn->n);
- return -EINVAL;
- }
-
- if (rang != 0) {
- dev_err(dev->class_dev, "Invalid range %d\n", insn->n);
- return -EINVAL;
- }
-
- if (aref != AREF_GROUND && aref != AREF_COMMON) {
- dev_err(dev->class_dev, "Invalid aref %d\n", insn->n);
- return -EINVAL;
- }
-
/* Stop any running conversion */
tmp = inl(dev->iobase + ME4000_AO_CTRL_REG(chan));
tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP;
@@ -1238,26 +1204,7 @@ static int me4000_ao_insn_write(struct comedi_device *dev,
outl(data[0], dev->iobase + ME4000_AO_SINGLE_REG(chan));
/* Store in the mirror */
- info->ao_readback[chan] = data[0];
-
- return 1;
-}
-
-static int me4000_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct me4000_info *info = dev->private;
- int chan = CR_CHAN(insn->chanspec);
-
- if (insn->n == 0) {
- return 0;
- } else if (insn->n > 1) {
- dev_err(dev->class_dev, "Invalid instruction length\n");
- return -EINVAL;
- }
-
- data[0] = info->ao_readback[chan];
+ s->readback[chan] = data[0];
return 1;
}
@@ -1507,7 +1454,11 @@ static int me4000_auto_attach(struct comedi_device *dev,
s->maxdata = 0xFFFF; /* 16 bit DAC */
s->range_table = &range_bipolar10;
s->insn_write = me4000_ao_insn_write;
- s->insn_read = me4000_ao_insn_read;
+ s->insn_read = comedi_readback_insn_read;
+
+ result = comedi_alloc_subdev_readback(s);
+ if (result)
+ return result;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -1563,11 +1514,9 @@ static int me4000_auto_attach(struct comedi_device *dev,
static void me4000_detach(struct comedi_device *dev)
{
- if (dev->irq)
- free_irq(dev->irq, dev);
if (dev->iobase)
me4000_reset(dev);
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver me4000_driver = {
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index 37a6fa92c656..00eaaf8ac148 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -171,7 +171,6 @@ struct me_private_data {
unsigned short control_1; /* Mirror of CONTROL_1 register */
unsigned short control_2; /* Mirror of CONTROL_2 register */
unsigned short dac_control; /* Mirror of the DAC_CONTROL register */
- int ao_readback[4]; /* Mirror of analog output data */
};
static inline void sleep(unsigned sec)
@@ -325,6 +324,7 @@ static int me_ao_insn_write(struct comedi_device *dev,
struct me_private_data *dev_private = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int rang = CR_RANGE(insn->chanspec);
+ unsigned int val = s->readback[chan];
int i;
/* Enable all DAC */
@@ -353,10 +353,11 @@ static int me_ao_insn_write(struct comedi_device *dev,
/* Set data register */
for (i = 0; i < insn->n; i++) {
- writew((data[0] & s->maxdata),
- dev->mmio + ME_DAC_DATA_A + (chan << 1));
- dev_private->ao_readback[chan] = (data[0] & s->maxdata);
+ val = data[i];
+
+ writew(val, dev->mmio + ME_DAC_DATA_A + (chan << 1));
}
+ s->readback[chan] = val;
/* Update dac with data registers */
readw(dev->mmio + ME_DAC_UPDATE);
@@ -364,21 +365,6 @@ static int me_ao_insn_write(struct comedi_device *dev,
return insn->n;
}
-static int me_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct me_private_data *dev_private = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int i;
-
- for (i = 0; i < insn->n; i++)
- data[i] = dev_private->ao_readback[chan];
-
- return insn->n;
-}
-
static int me2600_xilinx_download(struct comedi_device *dev,
const u8 *data, size_t size,
unsigned long context)
@@ -530,8 +516,12 @@ static int me_auto_attach(struct comedi_device *dev,
s->maxdata = 0x0fff;
s->len_chanlist = 4;
s->range_table = &me_ao_range;
- s->insn_read = me_ao_insn_read;
s->insn_write = me_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -554,14 +544,12 @@ static void me_detach(struct comedi_device *dev)
struct me_private_data *dev_private = dev->private;
if (dev_private) {
- if (dev->mmio) {
+ if (dev->mmio)
me_reset(dev);
- iounmap(dev->mmio);
- }
if (dev_private->plx_regbase)
iounmap(dev_private->plx_regbase);
}
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver me_daq_driver = {
diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c
index 464f4b4745c7..c8d3a22c5896 100644
--- a/drivers/staging/comedi/drivers/mf6x4.c
+++ b/drivers/staging/comedi/drivers/mf6x4.c
@@ -58,7 +58,6 @@
#define MF6X4_DA7_R 0x2e
/* Map DAC cahnnel id to real HW-dependent offset value */
#define MF6X4_DAC_R(x) (0x20 + ((x) * 2))
-#define MF6X4_DA_M 0x3fff
/* BAR2 registers */
#define MF634_GPIOC_R 0x68
@@ -101,9 +100,6 @@ struct mf6x4_private {
* offsets -- this variable makes the access easier
*/
void __iomem *gpioc_R;
-
- /* DAC value cache -- used for insn_read function */
- int ao_readback[8];
};
static int mf6x4_di_insn_bits(struct comedi_device *dev,
@@ -182,6 +178,7 @@ static int mf6x4_ao_insn_write(struct comedi_device *dev,
{
struct mf6x4_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = s->readback[chan];
uint32_t gpioc;
int i;
@@ -191,24 +188,10 @@ static int mf6x4_ao_insn_write(struct comedi_device *dev,
devpriv->gpioc_R);
for (i = 0; i < insn->n; i++) {
- iowrite16(data[i] & MF6X4_DA_M, dev->mmio + MF6X4_DAC_R(chan));
-
- devpriv->ao_readback[chan] = data[i];
+ val = data[i];
+ iowrite16(val, dev->mmio + MF6X4_DAC_R(chan));
}
-
- return insn->n;
-}
-
-static int mf6x4_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct mf6x4_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int i;
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
+ s->readback[chan] = val;
return insn->n;
}
@@ -276,7 +259,11 @@ static int mf6x4_auto_attach(struct comedi_device *dev, unsigned long context)
s->maxdata = 0x3fff; /* 14 bits DAC */
s->range_table = &range_bipolar10;
s->insn_write = mf6x4_ao_insn_write;
- s->insn_read = mf6x4_ao_insn_read;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
/* DIN */
s = &dev->subdevices[2];
@@ -303,14 +290,13 @@ static void mf6x4_detach(struct comedi_device *dev)
{
struct mf6x4_private *devpriv = dev->private;
- if (devpriv->bar0_mem)
- iounmap(devpriv->bar0_mem);
- if (dev->mmio)
- iounmap(dev->mmio);
- if (devpriv->bar2_mem)
- iounmap(devpriv->bar2_mem);
-
- comedi_pci_disable(dev);
+ if (devpriv) {
+ if (devpriv->bar0_mem)
+ iounmap(devpriv->bar0_mem);
+ if (devpriv->bar2_mem)
+ iounmap(devpriv->bar2_mem);
+ }
+ comedi_pci_detach(dev);
}
static struct comedi_driver mf6x4_driver = {
diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c
index e841a5a3ec4f..f710c8e81320 100644
--- a/drivers/staging/comedi/drivers/multiq3.c
+++ b/drivers/staging/comedi/drivers/multiq3.c
@@ -75,10 +75,6 @@ Devices: [Quanser Consulting] MultiQ-3 (multiq3)
#define MULTIQ3_TIMEOUT 30
-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,
@@ -126,38 +122,25 @@ static int multiq3_ai_insn_read(struct comedi_device *dev,
return n;
}
-static int multiq3_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct multiq3_private *devpriv = dev->private;
- int i;
- int chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return i;
-}
-
static int multiq3_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 multiq3_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = s->readback[chan];
int i;
- int chan = CR_CHAN(insn->chanspec);
for (i = 0; i < insn->n; i++) {
+ val = data[i];
outw(MULTIQ3_CONTROL_MUST | MULTIQ3_DA_LOAD | chan,
dev->iobase + MULTIQ3_CONTROL);
- outw(data[i], dev->iobase + MULTIQ3_DAC_DATA);
+ outw(val, dev->iobase + MULTIQ3_DAC_DATA);
outw(MULTIQ3_CONTROL_MUST, dev->iobase + MULTIQ3_CONTROL);
-
- devpriv->ao_readback[chan] = data[i];
}
+ s->readback[chan] = val;
- return i;
+ return insn->n;
}
static int multiq3_di_insn_bits(struct comedi_device *dev,
@@ -227,7 +210,6 @@ static void encoder_reset(struct comedi_device *dev)
static int multiq3_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- struct multiq3_private *devpriv;
struct comedi_subdevice *s;
int ret;
@@ -239,10 +221,6 @@ static int multiq3_attach(struct comedi_device *dev,
if (ret)
return ret;
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
s = &dev->subdevices[0];
/* ai subdevice */
s->type = COMEDI_SUBD_AI;
@@ -257,10 +235,14 @@ static int multiq3_attach(struct comedi_device *dev,
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE;
s->n_chan = 8;
- s->insn_read = multiq3_ao_insn_read;
- s->insn_write = multiq3_ao_insn_write;
s->maxdata = 0xfff;
s->range_table = &range_bipolar5;
+ s->insn_write = multiq3_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[2];
/* di subdevice */
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index e84dac2bf3b2..45fb601e4080 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -252,10 +252,9 @@ static int ni6527_intr_cmdtest(struct comedi_device *dev,
if (err)
return 3;
- /* step 4: fix up any arguments */
+ /* Step 4: fix up any arguments */
- if (err)
- return 4;
+ /* Step 5: check channel list if it exists */
return 0;
}
@@ -472,11 +471,7 @@ static void ni6527_detach(struct comedi_device *dev)
{
if (dev->mmio)
ni6527_reset(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->mmio)
- iounmap(dev->mmio);
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver ni6527_driver = {
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index 873941be56cb..3b642861eb36 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -294,7 +294,7 @@ MODULE_PARM_DESC(legacy_invert_outputs,
static unsigned int ni_65xx_num_ports(struct comedi_device *dev)
{
- const struct ni_65xx_board *board = comedi_board(dev);
+ const struct ni_65xx_board *board = dev->board_ptr;
return board->num_dio_ports + board->num_di_ports + board->num_do_ports;
}
@@ -548,10 +548,9 @@ static int ni_65xx_intr_cmdtest(struct comedi_device *dev,
if (err)
return 3;
- /* step 4: fix up any arguments */
+ /* Step 4: fix up any arguments */
- if (err)
- return 4;
+ /* Step 5: check channel list if it exists */
return 0;
}
@@ -793,13 +792,9 @@ static int ni_65xx_auto_attach(struct comedi_device *dev,
static void ni_65xx_detach(struct comedi_device *dev)
{
- if (dev->mmio) {
+ if (dev->mmio)
writeb(0x00, dev->mmio + NI_65XX_CTRL_REG);
- iounmap(dev->mmio);
- }
- if (dev->irq)
- free_irq(dev->irq, dev);
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
}
static struct comedi_driver ni_65xx_driver = {
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index b0b03d4d6081..5b6794c8232e 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -433,7 +433,7 @@ struct ni_660x_private {
static inline unsigned ni_660x_num_counters(struct comedi_device *dev)
{
- const struct ni_660x_board *board = comedi_board(dev);
+ const struct ni_660x_board *board = dev->board_ptr;
return board->n_chips * counters_per_chip;
}
@@ -852,7 +852,7 @@ static int ni_660x_allocate_private(struct comedi_device *dev)
static int ni_660x_alloc_mite_rings(struct comedi_device *dev)
{
- const struct ni_660x_board *board = comedi_board(dev);
+ const struct ni_660x_board *board = dev->board_ptr;
struct ni_660x_private *devpriv = dev->private;
unsigned i;
unsigned j;
@@ -870,7 +870,7 @@ static int ni_660x_alloc_mite_rings(struct comedi_device *dev)
static void ni_660x_free_mite_rings(struct comedi_device *dev)
{
- const struct ni_660x_board *board = comedi_board(dev);
+ const struct ni_660x_board *board = dev->board_ptr;
struct ni_660x_private *devpriv = dev->private;
unsigned i;
unsigned j;
@@ -924,7 +924,7 @@ static void ni_660x_select_pfi_output(struct comedi_device *dev,
unsigned pfi_channel,
unsigned output_select)
{
- const struct ni_660x_board *board = comedi_board(dev);
+ const struct ni_660x_board *board = dev->board_ptr;
static const unsigned counter_4_7_first_pfi = 8;
static const unsigned counter_4_7_last_pfi = 23;
unsigned active_chipset = 0;
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index f5caefad0b59..54721deb80cc 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -83,52 +83,38 @@ static const struct ni_670x_board ni_670x_boards[] = {
struct ni_670x_private {
int boardtype;
int dio;
- unsigned int ao_readback[32];
};
-static int ni_670x_ao_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int ni_670x_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct ni_670x_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = s->readback[chan];
int i;
- int chan = CR_CHAN(insn->chanspec);
-
- /* Channel number mapping :
-
- NI 6703/ NI 6704 | NI 6704 Only
- ----------------------------------------------------
- vch(0) : 0 | ich(16) : 1
- vch(1) : 2 | ich(17) : 3
- . : . | . .
- . : . | . .
- . : . | . .
- vch(15) : 30 | ich(31) : 31 */
+ /*
+ * Channel number mapping:
+ *
+ * NI 6703/ NI 6704 | NI 6704 Only
+ * -------------------------------
+ * vch(0) : 0 | ich(16) : 1
+ * vch(1) : 2 | ich(17) : 3
+ * ... | ...
+ * vch(15) : 30 | ich(31) : 31
+ */
for (i = 0; i < insn->n; i++) {
+ val = data[i];
/* First write in channel register which channel to use */
writel(((chan & 15) << 1) | ((chan & 16) >> 4),
dev->mmio + AO_CHAN_OFFSET);
/* write channel value */
- writel(data[i], dev->mmio + AO_VALUE_OFFSET);
- devpriv->ao_readback[chan] = data[i];
+ writel(val, dev->mmio + AO_VALUE_OFFSET);
}
+ s->readback[chan] = val;
- return i;
-}
-
-static int ni_670x_ao_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct ni_670x_private *devpriv = dev->private;
- int i;
- int chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return i;
+ return insn->n;
}
static int ni_670x_dio_insn_bits(struct comedi_device *dev,
@@ -241,8 +227,12 @@ static int ni_670x_auto_attach(struct comedi_device *dev,
} else {
s->range_table = &range_bipolar10;
}
- s->insn_write = &ni_670x_ao_winsn;
- s->insn_read = &ni_670x_ao_rinsn;
+ s->insn_write = ni_670x_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[1];
/* digital i/o subdevice */
@@ -266,14 +256,12 @@ static void ni_670x_detach(struct comedi_device *dev)
{
struct comedi_subdevice *s;
+ comedi_pci_detach(dev);
if (dev->n_subdevices) {
s = &dev->subdevices[0];
if (s)
kfree(s->range_table_list);
}
- if (dev->mmio)
- iounmap(dev->mmio);
- comedi_pci_disable(dev);
}
static struct comedi_driver ni_670x_driver = {
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index de67161f6185..72ec857d073e 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -287,7 +287,7 @@ static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
static int a2150_get_timing(struct comedi_device *dev, unsigned int *period,
unsigned int flags)
{
- const struct a2150_board *thisboard = comedi_board(dev);
+ const struct a2150_board *thisboard = dev->board_ptr;
struct a2150_private *devpriv = dev->private;
int lub, glb, temp;
int lub_divisor_shift, lub_index, glb_divisor_shift, glb_index;
@@ -326,8 +326,8 @@ static int a2150_get_timing(struct comedi_device *dev, unsigned int *period,
}
}
}
- switch (flags & TRIG_ROUND_MASK) {
- case TRIG_ROUND_NEAREST:
+ switch (flags & CMDF_ROUND_MASK) {
+ case CMDF_ROUND_NEAREST:
default:
/* if least upper bound is better approximation */
if (lub - *period < *period - glb)
@@ -335,10 +335,10 @@ static int a2150_get_timing(struct comedi_device *dev, unsigned int *period,
else
*period = glb;
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
*period = lub;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
*period = glb;
break;
}
@@ -436,7 +436,7 @@ static int a2150_ai_check_chanlist(struct comedi_device *dev,
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);
+ const struct a2150_board *thisboard = dev->board_ptr;
int err = 0;
unsigned int arg;
@@ -511,9 +511,9 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
unsigned int old_config_bits = devpriv->config_bits;
unsigned int trigger_bits;
- if (cmd->flags & TRIG_RT) {
+ if (cmd->flags & CMDF_PRIORITY) {
dev_err(dev->class_dev,
- "dma incompatible with hard real-time interrupt (TRIG_RT), aborting\n");
+ "dma incompatible with hard real-time interrupt (CMDF_PRIORITY), aborting\n");
return -1;
}
/* clear fifo and reset triggering circuitry */
@@ -705,8 +705,12 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- dev->board_ptr = a2150_boards + a2150_probe(dev);
- thisboard = comedi_board(dev);
+ i = a2150_probe(dev);
+ if (i >= ARRAY_SIZE(a2150_boards))
+ return -ENODEV;
+
+ dev->board_ptr = a2150_boards + i;
+ thisboard = dev->board_ptr;
dev->board_name = thisboard->name;
if ((irq >= 3 && irq <= 7) || (irq >= 9 && irq <= 12) ||
diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index c93b47bcca51..3e1ce5866147 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -118,9 +118,6 @@ struct atao_private {
unsigned short cfg1;
unsigned short cfg3;
- /* Used for AO readback */
- unsigned int ao_readback[10];
-
/* Used for caldac readback */
unsigned char caldac[21];
};
@@ -141,9 +138,8 @@ static int atao_ao_insn_write(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- struct atao_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int val;
+ unsigned int val = s->readback[chan];
int i;
if (chan == 0)
@@ -151,12 +147,12 @@ static int atao_ao_insn_write(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
val = data[i];
- devpriv->ao_readback[chan] = val;
- /* munge offset binary (unsigned) to two's complement */
- val = comedi_offset_munge(s, val);
- outw(val, dev->iobase + ATAO_AO_REG(chan));
+ /* the hardware expects two's complement values */
+ outw(comedi_offset_munge(s, val),
+ dev->iobase + ATAO_AO_REG(chan));
}
+ s->readback[chan] = val;
if (chan == 0)
atao_select_reg_group(dev, 0);
@@ -164,21 +160,6 @@ static int atao_ao_insn_write(struct comedi_device *dev,
return insn->n;
}
-static int atao_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct atao_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 atao_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -338,7 +319,7 @@ static void atao_reset(struct comedi_device *dev)
static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct atao_board *board = comedi_board(dev);
+ const struct atao_board *board = dev->board_ptr;
struct atao_private *devpriv;
struct comedi_subdevice *s;
int ret;
@@ -363,7 +344,11 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->maxdata = 0x0fff;
s->range_table = it->options[3] ? &range_unipolar10 : &range_bipolar10;
s->insn_write = atao_ao_insn_write;
- s->insn_read = atao_ao_insn_read;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
/* Digital I/O subdevice */
s = &dev->subdevices[1];
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index 2bd9f692a7ae..0c5ff287dcef 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -336,7 +336,7 @@ static int ni_atmio_attach(struct comedi_device *dev,
return -EIO;
dev->board_ptr = ni_boards + board;
- boardtype = comedi_board(dev);
+ boardtype = dev->board_ptr;
dev->board_name = boardtype->name;
/* irq stuff */
diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index 9c08da9508f4..fc3c19de7005 100644
--- a/drivers/staging/comedi/drivers/ni_atmio16d.c
+++ b/drivers/staging/comedi/drivers/ni_atmio16d.c
@@ -138,7 +138,6 @@ struct atmio16d_private {
enum { dac_internal, dac_external } dac0_reference, dac1_reference;
enum { dac_2comp, dac_straight } dac0_coding, dac1_coding;
const struct comedi_lrange *ao_range_type_list[2];
- unsigned int ao_readback[2];
unsigned int com_reg_1_state; /* current state of command register 1 */
unsigned int com_reg_2_state; /* current state of command register 2 */
};
@@ -275,11 +274,10 @@ static int atmio16d_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_COUNT) {
- /* any count is allowed */
- } else { /* TRIG_NONE */
+ 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;
@@ -496,48 +494,34 @@ static int atmio16d_ai_insn_read(struct comedi_device *dev,
return i;
}
-static int atmio16d_ao_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;
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
- return i;
-}
-
static int atmio16d_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 atmio16d_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int reg = (chan) ? DAC1_REG : DAC0_REG;
+ bool munge = false;
int i;
- int chan;
- int d;
- chan = CR_CHAN(insn->chanspec);
+ if (chan == 0 && devpriv->dac0_coding == dac_2comp)
+ munge = true;
+ if (chan == 1 && devpriv->dac1_coding == dac_2comp)
+ munge = true;
for (i = 0; i < insn->n; i++) {
- d = data[i];
- switch (chan) {
- case 0:
- if (devpriv->dac0_coding == dac_2comp)
- d ^= 0x800;
- outw(d, dev->iobase + DAC0_REG);
- break;
- case 1:
- if (devpriv->dac1_coding == dac_2comp)
- d ^= 0x800;
- outw(d, dev->iobase + DAC1_REG);
- break;
- default:
- return -EINVAL;
- }
- devpriv->ao_readback[chan] = data[i];
+ unsigned int val = data[i];
+
+ s->readback[chan] = val;
+
+ if (munge)
+ val ^= 0x800;
+
+ outw(val, dev->iobase + reg);
}
- return i;
+
+ return insn->n;
}
static int atmio16d_dio_insn_bits(struct comedi_device *dev,
@@ -617,7 +601,7 @@ static int atmio16d_dio_insn_config(struct comedi_device *dev,
static int atmio16d_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- const struct atmio16_board_t *board = comedi_board(dev);
+ const struct atmio16_board_t *board = dev->board_ptr;
struct atmio16d_private *devpriv;
struct comedi_subdevice *s;
int ret;
@@ -688,8 +672,6 @@ static int atmio16d_attach(struct comedi_device *dev,
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE;
s->n_chan = 2;
- s->insn_read = atmio16d_ao_insn_read;
- s->insn_write = atmio16d_ao_insn_write;
s->maxdata = 0xfff; /* 4095 decimal */
s->range_table_list = devpriv->ao_range_type_list;
switch (devpriv->dac0_range) {
@@ -708,6 +690,12 @@ static int atmio16d_attach(struct comedi_device *dev,
devpriv->ao_range_type_list[1] = &range_unipolar10;
break;
}
+ s->insn_write = atmio16d_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
/* Digital I/O */
s = &dev->subdevices[2];
@@ -722,7 +710,7 @@ static int atmio16d_attach(struct comedi_device *dev,
/* 8255 subdevice */
s = &dev->subdevices[3];
if (board->has_8255) {
- ret = subdev_8255_init(dev, s, NULL, dev->iobase);
+ ret = subdev_8255_init(dev, s, NULL, 0x00);
if (ret)
return ret;
} else {
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index 925e82c65b2d..8cfabdbaa30c 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -59,7 +59,7 @@ static int dio24_auto_attach(struct comedi_device *dev,
/* 8255 dio */
s = &dev->subdevices[0];
- ret = subdev_8255_init(dev, s, NULL, dev->iobase);
+ ret = subdev_8255_init(dev, s, NULL, 0x00);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 126d65cb39f2..1fbfdb4c80c0 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -58,99 +58,12 @@
*/
#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/delay.h>
#include "../comedidev.h"
-#include "8253.h"
-#include "8255.h"
-#include "comedi_fc.h"
#include "ni_labpc.h"
-#include "ni_labpc_regs.h"
#include "ni_labpc_isadma.h"
-enum scan_mode {
- MODE_SINGLE_CHAN,
- MODE_SINGLE_CHAN_INTERVAL,
- MODE_MULT_CHAN_UP,
- MODE_MULT_CHAN_DOWN,
-};
-
-static const struct comedi_lrange range_labpc_plus_ai = {
- 16, {
- BIP_RANGE(5),
- BIP_RANGE(4),
- BIP_RANGE(2.5),
- BIP_RANGE(1),
- BIP_RANGE(0.5),
- BIP_RANGE(0.25),
- BIP_RANGE(0.1),
- BIP_RANGE(0.05),
- UNI_RANGE(10),
- UNI_RANGE(8),
- UNI_RANGE(5),
- UNI_RANGE(2),
- UNI_RANGE(1),
- UNI_RANGE(0.5),
- UNI_RANGE(0.2),
- UNI_RANGE(0.1)
- }
-};
-
-static const struct comedi_lrange range_labpc_1200_ai = {
- 14, {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1),
- BIP_RANGE(0.5),
- BIP_RANGE(0.25),
- BIP_RANGE(0.1),
- BIP_RANGE(0.05),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2),
- UNI_RANGE(1),
- UNI_RANGE(0.5),
- UNI_RANGE(0.2),
- UNI_RANGE(0.1)
- }
-};
-
-static const struct comedi_lrange range_labpc_ao = {
- 2, {
- BIP_RANGE(5),
- UNI_RANGE(10)
- }
-};
-
-/* functions that do inb/outb and readb/writeb so we can use
- * function pointers to decide which to use */
-static unsigned int labpc_inb(struct comedi_device *dev, unsigned long reg)
-{
- return inb(dev->iobase + reg);
-}
-
-static void labpc_outb(struct comedi_device *dev,
- unsigned int byte, unsigned long reg)
-{
- outb(byte, dev->iobase + reg);
-}
-
-static unsigned int labpc_readb(struct comedi_device *dev, unsigned long reg)
-{
- return readb(dev->mmio + reg);
-}
-
-static void labpc_writeb(struct comedi_device *dev,
- unsigned int byte, unsigned long reg)
-{
- writeb(byte, dev->mmio + reg);
-}
-
-#if IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISA)
static const struct labpc_boardinfo labpc_boards[] = {
{
.name = "lab-pc-1200",
@@ -169,1284 +82,7 @@ static const struct labpc_boardinfo labpc_boards[] = {
.has_ao = 1,
},
};
-#endif
-
-static void labpc_counter_load(struct comedi_device *dev,
- unsigned long reg,
- unsigned int counter_number,
- unsigned int count,
- unsigned int mode)
-{
- if (dev->mmio) {
- i8254_mm_set_mode(dev->mmio + reg, 0, counter_number, mode);
- i8254_mm_write(dev->mmio + reg, 0, counter_number, count);
- } else {
- i8254_set_mode(dev->iobase + reg, 0, counter_number, mode);
- i8254_write(dev->iobase + reg, 0, counter_number, count);
- }
-}
-
-static void labpc_counter_set_mode(struct comedi_device *dev,
- unsigned long reg,
- unsigned int counter_number,
- unsigned int mode)
-{
- if (dev->mmio)
- i8254_mm_set_mode(dev->mmio + reg, 0, counter_number, mode);
- else
- i8254_set_mode(dev->iobase + reg, 0, counter_number, mode);
-}
-
-static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- struct labpc_private *devpriv = dev->private;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->cmd2 &= ~(CMD2_SWTRIG | CMD2_HWTRIG | CMD2_PRETRIG);
- devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- devpriv->cmd3 = 0;
- devpriv->write_byte(dev, devpriv->cmd3, CMD3_REG);
-
- return 0;
-}
-
-static void labpc_ai_set_chan_and_gain(struct comedi_device *dev,
- enum scan_mode mode,
- unsigned int chan,
- unsigned int range,
- unsigned int aref)
-{
- const struct labpc_boardinfo *board = comedi_board(dev);
- struct labpc_private *devpriv = dev->private;
-
- if (board->is_labpc1200) {
- /*
- * The LabPC-1200 boards do not have a gain
- * of '0x10'. Skip the range values that would
- * result in this gain.
- */
- range += (range > 0) + (range > 7);
- }
-
- /* munge channel bits for differential/scan disabled mode */
- if ((mode == MODE_SINGLE_CHAN || mode == MODE_SINGLE_CHAN_INTERVAL) &&
- aref == AREF_DIFF)
- chan *= 2;
- devpriv->cmd1 = CMD1_MA(chan);
- devpriv->cmd1 |= CMD1_GAIN(range);
-
- devpriv->write_byte(dev, devpriv->cmd1, CMD1_REG);
-}
-
-static void labpc_setup_cmd6_reg(struct comedi_device *dev,
- struct comedi_subdevice *s,
- enum scan_mode mode,
- enum transfer_type xfer,
- unsigned int range,
- unsigned int aref,
- bool ena_intr)
-{
- const struct labpc_boardinfo *board = comedi_board(dev);
- struct labpc_private *devpriv = dev->private;
-
- if (!board->is_labpc1200)
- return;
-
- /* reference inputs to ground or common? */
- if (aref != AREF_GROUND)
- devpriv->cmd6 |= CMD6_NRSE;
- else
- devpriv->cmd6 &= ~CMD6_NRSE;
-
- /* bipolar or unipolar range? */
- if (comedi_range_is_unipolar(s, range))
- devpriv->cmd6 |= CMD6_ADCUNI;
- else
- devpriv->cmd6 &= ~CMD6_ADCUNI;
-
- /* interrupt on fifo half full? */
- if (xfer == fifo_half_full_transfer)
- devpriv->cmd6 |= CMD6_HFINTEN;
- else
- devpriv->cmd6 &= ~CMD6_HFINTEN;
-
- /* enable interrupt on counter a1 terminal count? */
- if (ena_intr)
- devpriv->cmd6 |= CMD6_DQINTEN;
- else
- devpriv->cmd6 &= ~CMD6_DQINTEN;
-
- /* are we scanning up or down through channels? */
- if (mode == MODE_MULT_CHAN_UP)
- devpriv->cmd6 |= CMD6_SCANUP;
- else
- devpriv->cmd6 &= ~CMD6_SCANUP;
-
- devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG);
-}
-
-static unsigned int labpc_read_adc_fifo(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
- unsigned int lsb = devpriv->read_byte(dev, ADC_FIFO_REG);
- unsigned int msb = devpriv->read_byte(dev, ADC_FIFO_REG);
-
- return (msb << 8) | lsb;
-}
-
-static void labpc_clear_adc_fifo(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
-
- devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG);
- labpc_read_adc_fifo(dev);
-}
-
-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;
-
- devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG);
- if (devpriv->stat1 & STAT1_DAVAIL)
- return 0;
- return -EBUSY;
-}
-
-static int labpc_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct labpc_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int range = CR_RANGE(insn->chanspec);
- unsigned int aref = CR_AREF(insn->chanspec);
- int ret;
- int i;
-
- /* disable timed conversions, interrupt generation and dma */
- labpc_cancel(dev, s);
-
- labpc_ai_set_chan_and_gain(dev, MODE_SINGLE_CHAN, chan, range, aref);
-
- labpc_setup_cmd6_reg(dev, s, MODE_SINGLE_CHAN, fifo_not_empty_transfer,
- range, aref, false);
-
- /* setup cmd4 register */
- devpriv->cmd4 = 0;
- devpriv->cmd4 |= CMD4_ECLKRCV;
- /* single-ended/differential */
- if (aref == AREF_DIFF)
- devpriv->cmd4 |= CMD4_SEDIFF;
- devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG);
-
- /* initialize pacer counter to prevent any problems */
- labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 0, I8254_MODE2);
-
- labpc_clear_adc_fifo(dev);
-
- for (i = 0; i < insn->n; i++) {
- /* trigger conversion */
- devpriv->write_byte(dev, 0x1, ADC_START_CONVERT_REG);
-
- ret = comedi_timeout(dev, s, insn, labpc_ai_eoc, 0);
- if (ret)
- return ret;
-
- data[i] = labpc_read_adc_fifo(dev);
- }
-
- return insn->n;
-}
-
-static bool labpc_use_continuous_mode(const struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- if (mode == MODE_SINGLE_CHAN || cmd->scan_begin_src == TRIG_FOLLOW)
- return true;
-
- return false;
-}
-
-static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- if (cmd->convert_src != TRIG_TIMER)
- return 0;
-
- if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER)
- return cmd->scan_begin_arg;
-
- return cmd->convert_arg;
-}
-
-static void labpc_set_ai_convert_period(struct comedi_cmd *cmd,
- enum scan_mode mode, unsigned int ns)
-{
- if (cmd->convert_src != TRIG_TIMER)
- return;
-
- if (mode == MODE_SINGLE_CHAN &&
- cmd->scan_begin_src == TRIG_TIMER) {
- cmd->scan_begin_arg = ns;
- if (cmd->convert_arg > cmd->scan_begin_arg)
- cmd->convert_arg = cmd->scan_begin_arg;
- } else
- cmd->convert_arg = ns;
-}
-
-static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- if (cmd->scan_begin_src != TRIG_TIMER)
- return 0;
-
- if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
- return 0;
-
- return cmd->scan_begin_arg;
-}
-
-static void labpc_set_ai_scan_period(struct comedi_cmd *cmd,
- enum scan_mode mode, unsigned int ns)
-{
- if (cmd->scan_begin_src != TRIG_TIMER)
- return;
-
- if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
- return;
-
- cmd->scan_begin_arg = ns;
-}
-
-/* figures out what counter values to use based on command */
-static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- struct labpc_private *devpriv = dev->private;
- /* max value for 16 bit counter in mode 2 */
- const int max_counter_value = 0x10000;
- /* min value for 16 bit counter in mode 2 */
- const int min_counter_value = 2;
- unsigned int base_period;
- unsigned int scan_period;
- unsigned int convert_period;
-
- /*
- * if both convert and scan triggers are TRIG_TIMER, then they
- * both rely on counter b0
- */
- convert_period = labpc_ai_convert_period(cmd, mode);
- scan_period = labpc_ai_scan_period(cmd, mode);
- if (convert_period && scan_period) {
- /*
- * pick the lowest b0 divisor value we can (for maximum input
- * clock speed on convert and scan counters)
- */
- devpriv->divisor_b0 = (scan_period - 1) /
- (I8254_OSC_BASE_2MHZ * max_counter_value) + 1;
- if (devpriv->divisor_b0 < min_counter_value)
- devpriv->divisor_b0 = min_counter_value;
- if (devpriv->divisor_b0 > max_counter_value)
- devpriv->divisor_b0 = max_counter_value;
-
- base_period = I8254_OSC_BASE_2MHZ * devpriv->divisor_b0;
-
- /* set a0 for conversion frequency and b1 for scan frequency */
- switch (cmd->flags & TRIG_ROUND_MASK) {
- default:
- case TRIG_ROUND_NEAREST:
- devpriv->divisor_a0 =
- (convert_period + (base_period / 2)) / base_period;
- devpriv->divisor_b1 =
- (scan_period + (base_period / 2)) / base_period;
- break;
- case TRIG_ROUND_UP:
- devpriv->divisor_a0 =
- (convert_period + (base_period - 1)) / base_period;
- devpriv->divisor_b1 =
- (scan_period + (base_period - 1)) / base_period;
- break;
- case TRIG_ROUND_DOWN:
- devpriv->divisor_a0 = convert_period / base_period;
- devpriv->divisor_b1 = scan_period / base_period;
- break;
- }
- /* make sure a0 and b1 values are acceptable */
- if (devpriv->divisor_a0 < min_counter_value)
- devpriv->divisor_a0 = min_counter_value;
- if (devpriv->divisor_a0 > max_counter_value)
- devpriv->divisor_a0 = max_counter_value;
- if (devpriv->divisor_b1 < min_counter_value)
- devpriv->divisor_b1 = min_counter_value;
- if (devpriv->divisor_b1 > max_counter_value)
- devpriv->divisor_b1 = max_counter_value;
- /* write corrected timings to command */
- labpc_set_ai_convert_period(cmd, mode,
- base_period * devpriv->divisor_a0);
- labpc_set_ai_scan_period(cmd, mode,
- base_period * devpriv->divisor_b1);
- /*
- * if only one TRIG_TIMER is used, we can employ the generic
- * cascaded timing functions
- */
- } else if (scan_period) {
- /*
- * calculate cascaded counter values
- * that give desired scan timing
- */
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ,
- &devpriv->divisor_b1,
- &devpriv->divisor_b0,
- &scan_period, cmd->flags);
- labpc_set_ai_scan_period(cmd, mode, scan_period);
- } else if (convert_period) {
- /*
- * calculate cascaded counter values
- * that give desired conversion timing
- */
- i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ,
- &devpriv->divisor_a0,
- &devpriv->divisor_b0,
- &convert_period, cmd->flags);
- labpc_set_ai_convert_period(cmd, mode, convert_period);
- }
-}
-
-static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd)
-{
- unsigned int chan0;
- unsigned int chan1;
-
- if (cmd->chanlist_len == 1)
- return MODE_SINGLE_CHAN;
-
- /* chanlist may be NULL during cmdtest */
- if (cmd->chanlist == NULL)
- return MODE_MULT_CHAN_UP;
-
- chan0 = CR_CHAN(cmd->chanlist[0]);
- chan1 = CR_CHAN(cmd->chanlist[1]);
-
- if (chan0 < chan1)
- return MODE_MULT_CHAN_UP;
-
- if (chan0 > chan1)
- return MODE_MULT_CHAN_DOWN;
-
- return MODE_SINGLE_CHAN_INTERVAL;
-}
-
-static int labpc_ai_check_chanlist(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
-{
- 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;
-
- 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 (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 (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 (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;
- }
-
- if (range != range0) {
- dev_dbg(dev->class_dev,
- "entries in chanlist must all have the same range\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 labpc_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd)
-{
- const struct labpc_boardinfo *board = comedi_board(dev);
- int err = 0;
- int tmp, tmp2;
- unsigned int stop_mask;
- enum scan_mode mode;
-
- /* Step 1 : check if triggers are trivially valid */
-
- err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
- err |= cfc_check_trigger_src(&cmd->scan_begin_src,
- TRIG_TIMER | 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);
-
- stop_mask = TRIG_COUNT | TRIG_NONE;
- if (board->is_labpc1200)
- stop_mask |= TRIG_EXT;
- err |= cfc_check_trigger_src(&cmd->stop_src, stop_mask);
-
- if (err)
- return 1;
-
- /* Step 2a : make sure trigger sources are unique */
-
- err |= cfc_check_trigger_is_unique(cmd->start_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 */
-
- /* can't have external stop and start triggers at once */
- if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT)
- err++;
-
- 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 value is ignored */
- break;
- }
-
- if (!cmd->chanlist_len)
- err |= -EINVAL;
- err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
-
- if (cmd->convert_src == TRIG_TIMER)
- err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
- board->ai_speed);
-
- /* make sure scan timing is not too fast */
- if (cmd->scan_begin_src == TRIG_TIMER) {
- if (cmd->convert_src == TRIG_TIMER)
- err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
- cmd->convert_arg * cmd->chanlist_len);
- err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
- board->ai_speed * 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;
- /*
- * TRIG_EXT doesn't care since it doesn't
- * trigger off a numbered channel
- */
- default:
- break;
- }
-
- if (err)
- return 3;
-
- /* step 4: fix up any arguments */
-
- tmp = cmd->convert_arg;
- tmp2 = cmd->scan_begin_arg;
- mode = labpc_ai_scan_mode(cmd);
- labpc_adc_timing(dev, cmd, mode);
- if (tmp != cmd->convert_arg || tmp2 != cmd->scan_begin_arg)
- err++;
-
- if (err)
- return 4;
-
- /* 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;
-}
-
-static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- const struct labpc_boardinfo *board = comedi_board(dev);
- struct labpc_private *devpriv = dev->private;
- struct comedi_async *async = s->async;
- struct comedi_cmd *cmd = &async->cmd;
- enum scan_mode mode = labpc_ai_scan_mode(cmd);
- unsigned int chanspec = (mode == MODE_MULT_CHAN_UP)
- ? cmd->chanlist[cmd->chanlist_len - 1]
- : cmd->chanlist[0];
- unsigned int chan = CR_CHAN(chanspec);
- unsigned int range = CR_RANGE(chanspec);
- unsigned int aref = CR_AREF(chanspec);
- enum transfer_type xfer;
- unsigned long flags;
-
- /* make sure board is disabled before setting up acquisition */
- labpc_cancel(dev, s);
-
- /* initialize software conversion count */
- if (cmd->stop_src == TRIG_COUNT)
- devpriv->count = cmd->stop_arg * cmd->chanlist_len;
-
- /* setup hardware conversion counter */
- if (cmd->stop_src == TRIG_EXT) {
- /*
- * load counter a1 with count of 3
- * (pc+ manual says this is minimum allowed) using mode 0
- */
- labpc_counter_load(dev, COUNTER_A_BASE_REG,
- 1, 3, I8254_MODE0);
- } else {
- /* just put counter a1 in mode 0 to set its output low */
- labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 1, I8254_MODE0);
- }
-
- /* figure out what method we will use to transfer data */
- if (labpc_have_dma_chan(dev) &&
- /* dma unsafe at RT priority,
- * and too much setup time for TRIG_WAKE_EOS */
- (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0)
- xfer = isa_dma_transfer;
- else if (/* pc-plus has no fifo-half full interrupt */
- board->is_labpc1200 &&
- /* wake-end-of-scan should interrupt on fifo not empty */
- (cmd->flags & TRIG_WAKE_EOS) == 0 &&
- /* make sure we are taking more than just a few points */
- (cmd->stop_src != TRIG_COUNT || devpriv->count > 256))
- xfer = fifo_half_full_transfer;
- else
- xfer = fifo_not_empty_transfer;
- devpriv->current_transfer = xfer;
-
- labpc_ai_set_chan_and_gain(dev, mode, chan, range, aref);
-
- labpc_setup_cmd6_reg(dev, s, mode, xfer, range, aref,
- (cmd->stop_src == TRIG_EXT));
- /* manual says to set scan enable bit on second pass */
- if (mode == MODE_MULT_CHAN_UP || mode == MODE_MULT_CHAN_DOWN) {
- devpriv->cmd1 |= CMD1_SCANEN;
- /* need a brief delay before enabling scan, or scan
- * list will get screwed when you switch
- * between scan up to scan down mode - dunno why */
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd1, CMD1_REG);
- }
-
- devpriv->write_byte(dev, cmd->chanlist_len, INTERVAL_COUNT_REG);
- /* load count */
- devpriv->write_byte(dev, 0x1, INTERVAL_STROBE_REG);
-
- if (cmd->convert_src == TRIG_TIMER ||
- cmd->scan_begin_src == TRIG_TIMER) {
- /* set up pacing */
- labpc_adc_timing(dev, cmd, mode);
- /* load counter b0 in mode 3 */
- labpc_counter_load(dev, 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 */
- labpc_counter_load(dev, COUNTER_A_BASE_REG,
- 0, devpriv->divisor_a0, I8254_MODE2);
- } else {
- /* initialize pacer counter to prevent any problems */
- labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 0, I8254_MODE2);
- }
-
- /* set up scan pacing */
- if (labpc_ai_scan_period(cmd, mode)) {
- /* load counter b1 in mode 2 */
- labpc_counter_load(dev, COUNTER_B_BASE_REG,
- 1, devpriv->divisor_b1, I8254_MODE2);
- }
-
- labpc_clear_adc_fifo(dev);
-
- if (xfer == isa_dma_transfer)
- labpc_setup_dma(dev, s);
-
- /* enable error interrupts */
- devpriv->cmd3 |= CMD3_ERRINTEN;
- /* enable fifo not empty interrupt? */
- if (xfer == fifo_not_empty_transfer)
- devpriv->cmd3 |= CMD3_FIFOINTEN;
- devpriv->write_byte(dev, devpriv->cmd3, CMD3_REG);
-
- /* setup any external triggering/pacing (cmd4 register) */
- devpriv->cmd4 = 0;
- if (cmd->convert_src != TRIG_EXT)
- devpriv->cmd4 |= CMD4_ECLKRCV;
- /* XXX should discard first scan when using interval scanning
- * since manual says it is not synced with scan clock */
- if (!labpc_use_continuous_mode(cmd, mode)) {
- devpriv->cmd4 |= CMD4_INTSCAN;
- if (cmd->scan_begin_src == TRIG_EXT)
- devpriv->cmd4 |= CMD4_EOIRCV;
- }
- /* single-ended/differential */
- if (aref == AREF_DIFF)
- devpriv->cmd4 |= CMD4_SEDIFF;
- devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG);
-
- /* startup acquisition */
-
- spin_lock_irqsave(&dev->spinlock, flags);
-
- /* use 2 cascaded counters for pacing */
- devpriv->cmd2 |= CMD2_TBSEL;
-
- devpriv->cmd2 &= ~(CMD2_SWTRIG | CMD2_HWTRIG | CMD2_PRETRIG);
- if (cmd->start_src == TRIG_EXT)
- devpriv->cmd2 |= CMD2_HWTRIG;
- else
- devpriv->cmd2 |= CMD2_SWTRIG;
- if (cmd->stop_src == TRIG_EXT)
- devpriv->cmd2 |= (CMD2_HWTRIG | CMD2_PRETRIG);
-
- devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG);
-
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- return 0;
-}
-
-/* read all available samples from ai fifo */
-static int labpc_drain_fifo(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
- struct comedi_async *async = dev->read_subdev->async;
- struct comedi_cmd *cmd = &async->cmd;
- unsigned short data;
- const int timeout = 10000;
- unsigned int i;
-
- devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG);
-
- for (i = 0; (devpriv->stat1 & STAT1_DAVAIL) && i < timeout;
- i++) {
- /* quit if we have all the data we want */
- if (cmd->stop_src == TRIG_COUNT) {
- if (devpriv->count == 0)
- break;
- devpriv->count--;
- }
- data = labpc_read_adc_fifo(dev);
- cfc_write_to_buffer(dev->read_subdev, data);
- devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG);
- }
- if (i == timeout) {
- dev_err(dev->class_dev, "ai timeout, fifo never empties\n");
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- return -1;
- }
-
- return 0;
-}
-
-/* makes sure all data acquired by board is transferred to comedi (used
- * when acquisition is terminated by stop_src == TRIG_EXT). */
-static void labpc_drain_dregs(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
-
- if (devpriv->current_transfer == isa_dma_transfer)
- labpc_drain_dma(dev);
-
- labpc_drain_fifo(dev);
-}
-
-/* interrupt service routine */
-static irqreturn_t labpc_interrupt(int irq, void *d)
-{
- struct comedi_device *dev = d;
- const struct labpc_boardinfo *board = comedi_board(dev);
- struct labpc_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
- struct comedi_async *async;
- struct comedi_cmd *cmd;
-
- if (!dev->attached) {
- dev_err(dev->class_dev, "premature interrupt\n");
- return IRQ_HANDLED;
- }
-
- async = s->async;
- cmd = &async->cmd;
-
- /* read board status */
- devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG);
- if (board->is_labpc1200)
- devpriv->stat2 = devpriv->read_byte(dev, STAT2_REG);
-
- if ((devpriv->stat1 & (STAT1_GATA0 | STAT1_CNTINT | STAT1_OVERFLOW |
- STAT1_OVERRUN | STAT1_DAVAIL)) == 0
- && (devpriv->stat2 & STAT2_OUTA1) == 0
- && (devpriv->stat2 & STAT2_FIFONHF)) {
- return IRQ_NONE;
- }
-
- if (devpriv->stat1 & STAT1_OVERRUN) {
- /* clear error interrupt */
- devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG);
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- cfc_handle_events(dev, s);
- dev_err(dev->class_dev, "overrun\n");
- return IRQ_HANDLED;
- }
-
- if (devpriv->current_transfer == isa_dma_transfer)
- labpc_handle_dma_status(dev);
- else
- labpc_drain_fifo(dev);
-
- if (devpriv->stat1 & STAT1_CNTINT) {
- dev_err(dev->class_dev, "handled timer interrupt?\n");
- /* clear it */
- devpriv->write_byte(dev, 0x1, TIMER_CLEAR_REG);
- }
-
- if (devpriv->stat1 & STAT1_OVERFLOW) {
- /* clear error interrupt */
- devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG);
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- cfc_handle_events(dev, s);
- dev_err(dev->class_dev, "overflow\n");
- return IRQ_HANDLED;
- }
- /* handle external stop trigger */
- if (cmd->stop_src == TRIG_EXT) {
- if (devpriv->stat2 & STAT2_OUTA1) {
- labpc_drain_dregs(dev);
- async->events |= COMEDI_CB_EOA;
- }
- }
-
- /* TRIG_COUNT end of acquisition */
- if (cmd->stop_src == TRIG_COUNT) {
- if (devpriv->count == 0)
- async->events |= COMEDI_CB_EOA;
- }
-
- cfc_handle_events(dev, s);
- return IRQ_HANDLED;
-}
-
-static int labpc_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- const struct labpc_boardinfo *board = comedi_board(dev);
- struct labpc_private *devpriv = dev->private;
- int channel, range;
- unsigned long flags;
- int lsb, msb;
-
- channel = CR_CHAN(insn->chanspec);
-
- /* turn off pacing of analog output channel */
- /* note: hardware bug in daqcard-1200 means pacing cannot
- * be independently enabled/disabled for its the two channels */
- spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->cmd2 &= ~CMD2_LDAC(channel);
- devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- /* set range */
- if (board->is_labpc1200) {
- range = CR_RANGE(insn->chanspec);
- if (comedi_range_is_unipolar(s, range))
- devpriv->cmd6 |= CMD6_DACUNI(channel);
- else
- devpriv->cmd6 &= ~CMD6_DACUNI(channel);
- /* write to register */
- devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG);
- }
- /* send data */
- lsb = data[0] & 0xff;
- msb = (data[0] >> 8) & 0xff;
- devpriv->write_byte(dev, lsb, DAC_LSB_REG(channel));
- devpriv->write_byte(dev, msb, DAC_MSB_REG(channel));
-
- /* remember value for readback */
- devpriv->ao_value[channel] = data[0];
-
- return 1;
-}
-
-static int labpc_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct labpc_private *devpriv = dev->private;
-
- data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)];
-
- return 1;
-}
-
-static int labpc_8255_mmio(int dir, int port, int data, unsigned long arg)
-{
- struct comedi_device *dev = (struct comedi_device *)arg;
-
- if (dir) {
- writeb(data, dev->mmio + DIO_BASE_REG + port);
- return 0;
- }
-
- return readb(dev->mmio + DIO_BASE_REG + port);
-}
-
-/* lowlevel write to eeprom/dac */
-static void labpc_serial_out(struct comedi_device *dev, unsigned int value,
- unsigned int value_width)
-{
- struct labpc_private *devpriv = dev->private;
- int i;
-
- for (i = 1; i <= value_width; i++) {
- /* clear serial clock */
- devpriv->cmd5 &= ~CMD5_SCLK;
- /* send bits most significant bit first */
- if (value & (1 << (value_width - i)))
- devpriv->cmd5 |= CMD5_SDATA;
- else
- devpriv->cmd5 &= ~CMD5_SDATA;
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
- /* set clock to load bit */
- devpriv->cmd5 |= CMD5_SCLK;
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
- }
-}
-
-/* lowlevel read from eeprom */
-static unsigned int labpc_serial_in(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
- unsigned int value = 0;
- int i;
- const int value_width = 8; /* number of bits wide values are */
-
- for (i = 1; i <= value_width; i++) {
- /* set serial clock */
- devpriv->cmd5 |= CMD5_SCLK;
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
- /* clear clock bit */
- devpriv->cmd5 &= ~CMD5_SCLK;
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
- /* read bits most significant bit first */
- udelay(1);
- devpriv->stat2 = devpriv->read_byte(dev, STAT2_REG);
- if (devpriv->stat2 & STAT2_PROMOUT)
- value |= 1 << (value_width - i);
- }
-
- return value;
-}
-
-static unsigned int labpc_eeprom_read(struct comedi_device *dev,
- unsigned int address)
-{
- struct labpc_private *devpriv = dev->private;
- unsigned int value;
- /* bits to tell eeprom to expect a read */
- const int read_instruction = 0x3;
- /* 8 bit write lengths to eeprom */
- const int write_length = 8;
-
- /* enable read/write to eeprom */
- devpriv->cmd5 &= ~CMD5_EEPROMCS;
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
- devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT);
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
-
- /* send read instruction */
- labpc_serial_out(dev, read_instruction, write_length);
- /* send 8 bit address to read from */
- labpc_serial_out(dev, address, write_length);
- /* read result */
- value = labpc_serial_in(dev);
-
- /* disable read/write to eeprom */
- devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT);
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
-
- return value;
-}
-
-static unsigned int labpc_eeprom_read_status(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
- unsigned int value;
- const int read_status_instruction = 0x5;
- const int write_length = 8; /* 8 bit write lengths to eeprom */
-
- /* enable read/write to eeprom */
- devpriv->cmd5 &= ~CMD5_EEPROMCS;
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
- devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT);
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
-
- /* send read status instruction */
- labpc_serial_out(dev, read_status_instruction, write_length);
- /* read result */
- value = labpc_serial_in(dev);
-
- /* disable read/write to eeprom */
- devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT);
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
-
- return value;
-}
-
-static int labpc_eeprom_write(struct comedi_device *dev,
- unsigned int address, unsigned int value)
-{
- struct labpc_private *devpriv = dev->private;
- const int write_enable_instruction = 0x6;
- const int write_instruction = 0x2;
- const int write_length = 8; /* 8 bit write lengths to eeprom */
- const int write_in_progress_bit = 0x1;
- const int timeout = 10000;
- int i;
-
- /* make sure there isn't already a write in progress */
- for (i = 0; i < timeout; i++) {
- if ((labpc_eeprom_read_status(dev) & write_in_progress_bit) ==
- 0)
- break;
- }
- if (i == timeout) {
- dev_err(dev->class_dev, "eeprom write timed out\n");
- return -ETIME;
- }
- /* update software copy of eeprom */
- devpriv->eeprom_data[address] = value;
-
- /* enable read/write to eeprom */
- devpriv->cmd5 &= ~CMD5_EEPROMCS;
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
- devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT);
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
-
- /* send write_enable instruction */
- labpc_serial_out(dev, write_enable_instruction, write_length);
- devpriv->cmd5 &= ~CMD5_EEPROMCS;
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
-
- /* send write instruction */
- devpriv->cmd5 |= CMD5_EEPROMCS;
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
- labpc_serial_out(dev, write_instruction, write_length);
- /* send 8 bit address to write to */
- labpc_serial_out(dev, address, write_length);
- /* write value */
- labpc_serial_out(dev, value, write_length);
- devpriv->cmd5 &= ~CMD5_EEPROMCS;
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
-
- /* disable read/write to eeprom */
- devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT);
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
-
- return 0;
-}
-
-/* writes to 8 bit calibration dacs */
-static void write_caldac(struct comedi_device *dev, unsigned int channel,
- unsigned int value)
-{
- struct labpc_private *devpriv = dev->private;
-
- if (value == devpriv->caldac[channel])
- return;
- devpriv->caldac[channel] = value;
-
- /* clear caldac load bit and make sure we don't write to eeprom */
- devpriv->cmd5 &= ~(CMD5_CALDACLD | CMD5_EEPROMCS | CMD5_WRTPRT);
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
-
- /* write 4 bit channel */
- labpc_serial_out(dev, channel, 4);
- /* write 8 bit caldac value */
- labpc_serial_out(dev, value, 8);
-
- /* set and clear caldac bit to load caldac value */
- devpriv->cmd5 |= CMD5_CALDACLD;
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
- devpriv->cmd5 &= ~CMD5_CALDACLD;
- udelay(1);
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
-}
-
-static int labpc_calib_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- unsigned int chan = CR_CHAN(insn->chanspec);
-
- /*
- * Only write the last data value to the caldac. Preceding
- * data would be overwritten anyway.
- */
- if (insn->n > 0)
- write_caldac(dev, chan, data[insn->n - 1]);
-
- return insn->n;
-}
-
-static int labpc_calib_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct labpc_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int i;
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->caldac[chan];
-
- return insn->n;
-}
-
-static int labpc_eeprom_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- unsigned int chan = CR_CHAN(insn->chanspec);
- int ret;
-
- /* only allow writes to user area of eeprom */
- if (chan < 16 || chan > 127)
- return -EINVAL;
-
- /*
- * Only write the last data value to the eeprom. Preceding
- * data would be overwritten anyway.
- */
- if (insn->n > 0) {
- ret = labpc_eeprom_write(dev, chan, data[insn->n - 1]);
- if (ret)
- return ret;
- }
-
- return insn->n;
-}
-
-static int labpc_eeprom_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct labpc_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int i;
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->eeprom_data[chan];
-
- return insn->n;
-}
-
-int labpc_common_attach(struct comedi_device *dev,
- unsigned int irq, unsigned long isr_flags)
-{
- const struct labpc_boardinfo *board = comedi_board(dev);
- struct labpc_private *devpriv = dev->private;
- struct comedi_subdevice *s;
- int ret;
- int i;
-
- if (dev->mmio) {
- devpriv->read_byte = labpc_readb;
- devpriv->write_byte = labpc_writeb;
- } else {
- devpriv->read_byte = labpc_inb;
- devpriv->write_byte = labpc_outb;
- }
-
- /* initialize board's command registers */
- devpriv->write_byte(dev, devpriv->cmd1, CMD1_REG);
- devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG);
- devpriv->write_byte(dev, devpriv->cmd3, CMD3_REG);
- devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG);
- if (board->is_labpc1200) {
- devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
- devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG);
- }
-
- if (irq) {
- ret = request_irq(irq, labpc_interrupt, isr_flags,
- dev->board_name, dev);
- if (ret == 0)
- dev->irq = irq;
- }
-
- ret = comedi_alloc_subdevices(dev, 5);
- if (ret)
- return ret;
-
- /* analog input subdevice */
- s = &dev->subdevices[0];
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF;
- s->n_chan = 8;
- s->len_chanlist = 8;
- s->maxdata = 0x0fff;
- s->range_table = board->is_labpc1200
- ? &range_labpc_1200_ai : &range_labpc_plus_ai;
- s->insn_read = labpc_ai_insn_read;
- if (dev->irq) {
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->do_cmd = labpc_ai_cmd;
- s->do_cmdtest = labpc_ai_cmdtest;
- s->cancel = labpc_cancel;
- }
-
- /* analog output */
- s = &dev->subdevices[1];
- if (board->has_ao) {
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
- s->n_chan = NUM_AO_CHAN;
- s->maxdata = 0x0fff;
- s->range_table = &range_labpc_ao;
- s->insn_read = labpc_ao_insn_read;
- s->insn_write = labpc_ao_insn_write;
-
- /* initialize analog outputs to a known value */
- for (i = 0; i < s->n_chan; i++) {
- short lsb, msb;
-
- devpriv->ao_value[i] = s->maxdata / 2;
- lsb = devpriv->ao_value[i] & 0xff;
- msb = (devpriv->ao_value[i] >> 8) & 0xff;
- devpriv->write_byte(dev, lsb, DAC_LSB_REG(i));
- devpriv->write_byte(dev, msb, DAC_MSB_REG(i));
- }
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- /* 8255 dio */
- s = &dev->subdevices[2];
- if (dev->mmio) {
- ret = subdev_8255_init(dev, s, labpc_8255_mmio,
- (unsigned long)dev);
- } else {
- ret = subdev_8255_init(dev, s, NULL,
- dev->iobase + DIO_BASE_REG);
- }
- if (ret)
- return ret;
-
- /* calibration subdevices for boards that have one */
- s = &dev->subdevices[3];
- if (board->is_labpc1200) {
- s->type = COMEDI_SUBD_CALIB;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
- s->n_chan = 16;
- s->maxdata = 0xff;
- s->insn_read = labpc_calib_insn_read;
- s->insn_write = labpc_calib_insn_write;
-
- for (i = 0; i < s->n_chan; i++)
- write_caldac(dev, i, s->maxdata / 2);
- } else
- s->type = COMEDI_SUBD_UNUSED;
-
- /* EEPROM */
- s = &dev->subdevices[4];
- if (board->is_labpc1200) {
- s->type = COMEDI_SUBD_MEMORY;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
- s->n_chan = EEPROM_SIZE;
- s->maxdata = 0xff;
- s->insn_read = labpc_eeprom_insn_read;
- s->insn_write = labpc_eeprom_insn_write;
-
- for (i = 0; i < s->n_chan; i++)
- devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
- } else
- s->type = COMEDI_SUBD_UNUSED;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(labpc_common_attach);
-
-#if IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISA)
static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct labpc_private *devpriv;
@@ -1492,19 +128,7 @@ static struct comedi_driver labpc_driver = {
.offset = sizeof(struct labpc_boardinfo),
};
module_comedi_driver(labpc_driver);
-#else
-static int __init labpc_common_init(void)
-{
- return 0;
-}
-module_init(labpc_common_init);
-
-static void __exit labpc_common_exit(void)
-{
-}
-module_exit(labpc_common_exit);
-#endif
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for NI Lab-PC ISA boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_labpc_common.c b/drivers/staging/comedi/drivers/ni_labpc_common.c
new file mode 100644
index 000000000000..35bc2c25ddfb
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_labpc_common.c
@@ -0,0 +1,1387 @@
+/*
+ * comedi/drivers/ni_labpc_common.c
+ *
+ * Common support code for "ni_labpc", "ni_labpc_pci" and "ni_labpc_cs".
+ *
+ * Copyright (C) 2001-2003 Frank Mori Hess <fmhess@users.sourceforge.net>
+ *
+ * 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 <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include "../comedidev.h"
+
+#include "8253.h"
+#include "8255.h"
+#include "comedi_fc.h"
+#include "ni_labpc.h"
+#include "ni_labpc_regs.h"
+#include "ni_labpc_isadma.h"
+
+enum scan_mode {
+ MODE_SINGLE_CHAN,
+ MODE_SINGLE_CHAN_INTERVAL,
+ MODE_MULT_CHAN_UP,
+ MODE_MULT_CHAN_DOWN,
+};
+
+static const struct comedi_lrange range_labpc_plus_ai = {
+ 16, {
+ BIP_RANGE(5),
+ BIP_RANGE(4),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.25),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.05),
+ UNI_RANGE(10),
+ UNI_RANGE(8),
+ UNI_RANGE(5),
+ UNI_RANGE(2),
+ UNI_RANGE(1),
+ UNI_RANGE(0.5),
+ UNI_RANGE(0.2),
+ UNI_RANGE(0.1)
+ }
+};
+
+static const struct comedi_lrange range_labpc_1200_ai = {
+ 14, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.25),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.05),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2),
+ UNI_RANGE(1),
+ UNI_RANGE(0.5),
+ UNI_RANGE(0.2),
+ UNI_RANGE(0.1)
+ }
+};
+
+static const struct comedi_lrange range_labpc_ao = {
+ 2, {
+ BIP_RANGE(5),
+ UNI_RANGE(10)
+ }
+};
+
+/* functions that do inb/outb and readb/writeb so we can use
+ * function pointers to decide which to use */
+static unsigned int labpc_inb(struct comedi_device *dev, unsigned long reg)
+{
+ return inb(dev->iobase + reg);
+}
+
+static void labpc_outb(struct comedi_device *dev,
+ unsigned int byte, unsigned long reg)
+{
+ outb(byte, dev->iobase + reg);
+}
+
+static unsigned int labpc_readb(struct comedi_device *dev, unsigned long reg)
+{
+ return readb(dev->mmio + reg);
+}
+
+static void labpc_writeb(struct comedi_device *dev,
+ unsigned int byte, unsigned long reg)
+{
+ writeb(byte, dev->mmio + reg);
+}
+
+static void labpc_counter_load(struct comedi_device *dev,
+ unsigned long reg,
+ unsigned int counter_number,
+ unsigned int count,
+ unsigned int mode)
+{
+ if (dev->mmio) {
+ i8254_mm_set_mode(dev->mmio + reg, 0, counter_number, mode);
+ i8254_mm_write(dev->mmio + reg, 0, counter_number, count);
+ } else {
+ i8254_set_mode(dev->iobase + reg, 0, counter_number, mode);
+ i8254_write(dev->iobase + reg, 0, counter_number, count);
+ }
+}
+
+static void labpc_counter_set_mode(struct comedi_device *dev,
+ unsigned long reg,
+ unsigned int counter_number,
+ unsigned int mode)
+{
+ if (dev->mmio)
+ i8254_mm_set_mode(dev->mmio + reg, 0, counter_number, mode);
+ else
+ i8254_set_mode(dev->iobase + reg, 0, counter_number, mode);
+}
+
+static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->spinlock, flags);
+ devpriv->cmd2 &= ~(CMD2_SWTRIG | CMD2_HWTRIG | CMD2_PRETRIG);
+ devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+
+ devpriv->cmd3 = 0;
+ devpriv->write_byte(dev, devpriv->cmd3, CMD3_REG);
+
+ return 0;
+}
+
+static void labpc_ai_set_chan_and_gain(struct comedi_device *dev,
+ enum scan_mode mode,
+ unsigned int chan,
+ unsigned int range,
+ unsigned int aref)
+{
+ const struct labpc_boardinfo *board = dev->board_ptr;
+ struct labpc_private *devpriv = dev->private;
+
+ if (board->is_labpc1200) {
+ /*
+ * The LabPC-1200 boards do not have a gain
+ * of '0x10'. Skip the range values that would
+ * result in this gain.
+ */
+ range += (range > 0) + (range > 7);
+ }
+
+ /* munge channel bits for differential/scan disabled mode */
+ if ((mode == MODE_SINGLE_CHAN || mode == MODE_SINGLE_CHAN_INTERVAL) &&
+ aref == AREF_DIFF)
+ chan *= 2;
+ devpriv->cmd1 = CMD1_MA(chan);
+ devpriv->cmd1 |= CMD1_GAIN(range);
+
+ devpriv->write_byte(dev, devpriv->cmd1, CMD1_REG);
+}
+
+static void labpc_setup_cmd6_reg(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ enum scan_mode mode,
+ enum transfer_type xfer,
+ unsigned int range,
+ unsigned int aref,
+ bool ena_intr)
+{
+ const struct labpc_boardinfo *board = dev->board_ptr;
+ struct labpc_private *devpriv = dev->private;
+
+ if (!board->is_labpc1200)
+ return;
+
+ /* reference inputs to ground or common? */
+ if (aref != AREF_GROUND)
+ devpriv->cmd6 |= CMD6_NRSE;
+ else
+ devpriv->cmd6 &= ~CMD6_NRSE;
+
+ /* bipolar or unipolar range? */
+ if (comedi_range_is_unipolar(s, range))
+ devpriv->cmd6 |= CMD6_ADCUNI;
+ else
+ devpriv->cmd6 &= ~CMD6_ADCUNI;
+
+ /* interrupt on fifo half full? */
+ if (xfer == fifo_half_full_transfer)
+ devpriv->cmd6 |= CMD6_HFINTEN;
+ else
+ devpriv->cmd6 &= ~CMD6_HFINTEN;
+
+ /* enable interrupt on counter a1 terminal count? */
+ if (ena_intr)
+ devpriv->cmd6 |= CMD6_DQINTEN;
+ else
+ devpriv->cmd6 &= ~CMD6_DQINTEN;
+
+ /* are we scanning up or down through channels? */
+ if (mode == MODE_MULT_CHAN_UP)
+ devpriv->cmd6 |= CMD6_SCANUP;
+ else
+ devpriv->cmd6 &= ~CMD6_SCANUP;
+
+ devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG);
+}
+
+static unsigned int labpc_read_adc_fifo(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int lsb = devpriv->read_byte(dev, ADC_FIFO_REG);
+ unsigned int msb = devpriv->read_byte(dev, ADC_FIFO_REG);
+
+ return (msb << 8) | lsb;
+}
+
+static void labpc_clear_adc_fifo(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG);
+ labpc_read_adc_fifo(dev);
+}
+
+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;
+
+ devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG);
+ if (devpriv->stat1 & STAT1_DAVAIL)
+ return 0;
+ return -EBUSY;
+}
+
+static int labpc_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int aref = CR_AREF(insn->chanspec);
+ int ret;
+ int i;
+
+ /* disable timed conversions, interrupt generation and dma */
+ labpc_cancel(dev, s);
+
+ labpc_ai_set_chan_and_gain(dev, MODE_SINGLE_CHAN, chan, range, aref);
+
+ labpc_setup_cmd6_reg(dev, s, MODE_SINGLE_CHAN, fifo_not_empty_transfer,
+ range, aref, false);
+
+ /* setup cmd4 register */
+ devpriv->cmd4 = 0;
+ devpriv->cmd4 |= CMD4_ECLKRCV;
+ /* single-ended/differential */
+ if (aref == AREF_DIFF)
+ devpriv->cmd4 |= CMD4_SEDIFF;
+ devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG);
+
+ /* initialize pacer counter to prevent any problems */
+ labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 0, I8254_MODE2);
+
+ labpc_clear_adc_fifo(dev);
+
+ for (i = 0; i < insn->n; i++) {
+ /* trigger conversion */
+ devpriv->write_byte(dev, 0x1, ADC_START_CONVERT_REG);
+
+ ret = comedi_timeout(dev, s, insn, labpc_ai_eoc, 0);
+ if (ret)
+ return ret;
+
+ data[i] = labpc_read_adc_fifo(dev);
+ }
+
+ return insn->n;
+}
+
+static bool labpc_use_continuous_mode(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
+{
+ if (mode == MODE_SINGLE_CHAN || cmd->scan_begin_src == TRIG_FOLLOW)
+ return true;
+
+ return false;
+}
+
+static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
+{
+ if (cmd->convert_src != TRIG_TIMER)
+ return 0;
+
+ if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER)
+ return cmd->scan_begin_arg;
+
+ return cmd->convert_arg;
+}
+
+static void labpc_set_ai_convert_period(struct comedi_cmd *cmd,
+ enum scan_mode mode, unsigned int ns)
+{
+ if (cmd->convert_src != TRIG_TIMER)
+ return;
+
+ if (mode == MODE_SINGLE_CHAN &&
+ cmd->scan_begin_src == TRIG_TIMER) {
+ cmd->scan_begin_arg = ns;
+ if (cmd->convert_arg > cmd->scan_begin_arg)
+ cmd->convert_arg = cmd->scan_begin_arg;
+ } else {
+ cmd->convert_arg = ns;
+ }
+}
+
+static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
+{
+ if (cmd->scan_begin_src != TRIG_TIMER)
+ return 0;
+
+ if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
+ return 0;
+
+ return cmd->scan_begin_arg;
+}
+
+static void labpc_set_ai_scan_period(struct comedi_cmd *cmd,
+ enum scan_mode mode, unsigned int ns)
+{
+ if (cmd->scan_begin_src != TRIG_TIMER)
+ return;
+
+ if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
+ return;
+
+ cmd->scan_begin_arg = ns;
+}
+
+/* figures out what counter values to use based on command */
+static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
+ enum scan_mode mode)
+{
+ struct labpc_private *devpriv = dev->private;
+ /* max value for 16 bit counter in mode 2 */
+ const int max_counter_value = 0x10000;
+ /* min value for 16 bit counter in mode 2 */
+ const int min_counter_value = 2;
+ unsigned int base_period;
+ unsigned int scan_period;
+ unsigned int convert_period;
+
+ /*
+ * if both convert and scan triggers are TRIG_TIMER, then they
+ * both rely on counter b0
+ */
+ convert_period = labpc_ai_convert_period(cmd, mode);
+ scan_period = labpc_ai_scan_period(cmd, mode);
+ if (convert_period && scan_period) {
+ /*
+ * pick the lowest b0 divisor value we can (for maximum input
+ * clock speed on convert and scan counters)
+ */
+ devpriv->divisor_b0 = (scan_period - 1) /
+ (I8254_OSC_BASE_2MHZ * max_counter_value) + 1;
+ if (devpriv->divisor_b0 < min_counter_value)
+ devpriv->divisor_b0 = min_counter_value;
+ if (devpriv->divisor_b0 > max_counter_value)
+ devpriv->divisor_b0 = max_counter_value;
+
+ base_period = I8254_OSC_BASE_2MHZ * devpriv->divisor_b0;
+
+ /* set a0 for conversion frequency and b1 for scan frequency */
+ switch (cmd->flags & CMDF_ROUND_MASK) {
+ default:
+ case CMDF_ROUND_NEAREST:
+ devpriv->divisor_a0 =
+ (convert_period + (base_period / 2)) / base_period;
+ devpriv->divisor_b1 =
+ (scan_period + (base_period / 2)) / base_period;
+ break;
+ case CMDF_ROUND_UP:
+ devpriv->divisor_a0 =
+ (convert_period + (base_period - 1)) / base_period;
+ devpriv->divisor_b1 =
+ (scan_period + (base_period - 1)) / base_period;
+ break;
+ case CMDF_ROUND_DOWN:
+ devpriv->divisor_a0 = convert_period / base_period;
+ devpriv->divisor_b1 = scan_period / base_period;
+ break;
+ }
+ /* make sure a0 and b1 values are acceptable */
+ if (devpriv->divisor_a0 < min_counter_value)
+ devpriv->divisor_a0 = min_counter_value;
+ if (devpriv->divisor_a0 > max_counter_value)
+ devpriv->divisor_a0 = max_counter_value;
+ if (devpriv->divisor_b1 < min_counter_value)
+ devpriv->divisor_b1 = min_counter_value;
+ if (devpriv->divisor_b1 > max_counter_value)
+ devpriv->divisor_b1 = max_counter_value;
+ /* write corrected timings to command */
+ labpc_set_ai_convert_period(cmd, mode,
+ base_period * devpriv->divisor_a0);
+ labpc_set_ai_scan_period(cmd, mode,
+ base_period * devpriv->divisor_b1);
+ /*
+ * if only one TRIG_TIMER is used, we can employ the generic
+ * cascaded timing functions
+ */
+ } else if (scan_period) {
+ /*
+ * calculate cascaded counter values
+ * that give desired scan timing
+ */
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ,
+ &devpriv->divisor_b1,
+ &devpriv->divisor_b0,
+ &scan_period, cmd->flags);
+ labpc_set_ai_scan_period(cmd, mode, scan_period);
+ } else if (convert_period) {
+ /*
+ * calculate cascaded counter values
+ * that give desired conversion timing
+ */
+ i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ,
+ &devpriv->divisor_a0,
+ &devpriv->divisor_b0,
+ &convert_period, cmd->flags);
+ labpc_set_ai_convert_period(cmd, mode, convert_period);
+ }
+}
+
+static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd)
+{
+ unsigned int chan0;
+ unsigned int chan1;
+
+ if (cmd->chanlist_len == 1)
+ return MODE_SINGLE_CHAN;
+
+ /* chanlist may be NULL during cmdtest */
+ if (cmd->chanlist == NULL)
+ return MODE_MULT_CHAN_UP;
+
+ chan0 = CR_CHAN(cmd->chanlist[0]);
+ chan1 = CR_CHAN(cmd->chanlist[1]);
+
+ if (chan0 < chan1)
+ return MODE_MULT_CHAN_UP;
+
+ if (chan0 > chan1)
+ return MODE_MULT_CHAN_DOWN;
+
+ return MODE_SINGLE_CHAN_INTERVAL;
+}
+
+static int labpc_ai_check_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ 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;
+
+ 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 (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 (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 (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;
+ }
+
+ if (range != range0) {
+ dev_dbg(dev->class_dev,
+ "entries in chanlist must all have the same range\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 labpc_ai_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s, struct comedi_cmd *cmd)
+{
+ const struct labpc_boardinfo *board = dev->board_ptr;
+ int err = 0;
+ int tmp, tmp2;
+ unsigned int stop_mask;
+ enum scan_mode mode;
+
+ /* Step 1 : check if triggers are trivially valid */
+
+ err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
+ err |= cfc_check_trigger_src(&cmd->scan_begin_src,
+ TRIG_TIMER | 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);
+
+ stop_mask = TRIG_COUNT | TRIG_NONE;
+ if (board->is_labpc1200)
+ stop_mask |= TRIG_EXT;
+ err |= cfc_check_trigger_src(&cmd->stop_src, stop_mask);
+
+ if (err)
+ return 1;
+
+ /* Step 2a : make sure trigger sources are unique */
+
+ err |= cfc_check_trigger_is_unique(cmd->start_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 */
+
+ /* can't have external stop and start triggers at once */
+ if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT)
+ err++;
+
+ 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 value is ignored */
+ break;
+ }
+
+ if (!cmd->chanlist_len)
+ err |= -EINVAL;
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+
+ if (cmd->convert_src == TRIG_TIMER)
+ err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
+ board->ai_speed);
+
+ /* make sure scan timing is not too fast */
+ if (cmd->scan_begin_src == TRIG_TIMER) {
+ if (cmd->convert_src == TRIG_TIMER)
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ cmd->convert_arg * cmd->chanlist_len);
+ err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
+ board->ai_speed * 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;
+ /*
+ * TRIG_EXT doesn't care since it doesn't
+ * trigger off a numbered channel
+ */
+ default:
+ break;
+ }
+
+ if (err)
+ return 3;
+
+ /* step 4: fix up any arguments */
+
+ tmp = cmd->convert_arg;
+ tmp2 = cmd->scan_begin_arg;
+ mode = labpc_ai_scan_mode(cmd);
+ labpc_adc_timing(dev, cmd, mode);
+ if (tmp != cmd->convert_arg || tmp2 != cmd->scan_begin_arg)
+ err++;
+
+ if (err)
+ return 4;
+
+ /* 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;
+}
+
+static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+ const struct labpc_boardinfo *board = dev->board_ptr;
+ struct labpc_private *devpriv = dev->private;
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ enum scan_mode mode = labpc_ai_scan_mode(cmd);
+ unsigned int chanspec = (mode == MODE_MULT_CHAN_UP) ?
+ cmd->chanlist[cmd->chanlist_len - 1] :
+ cmd->chanlist[0];
+ unsigned int chan = CR_CHAN(chanspec);
+ unsigned int range = CR_RANGE(chanspec);
+ unsigned int aref = CR_AREF(chanspec);
+ enum transfer_type xfer;
+ unsigned long flags;
+
+ /* make sure board is disabled before setting up acquisition */
+ labpc_cancel(dev, s);
+
+ /* initialize software conversion count */
+ if (cmd->stop_src == TRIG_COUNT)
+ devpriv->count = cmd->stop_arg * cmd->chanlist_len;
+
+ /* setup hardware conversion counter */
+ if (cmd->stop_src == TRIG_EXT) {
+ /*
+ * load counter a1 with count of 3
+ * (pc+ manual says this is minimum allowed) using mode 0
+ */
+ labpc_counter_load(dev, COUNTER_A_BASE_REG,
+ 1, 3, I8254_MODE0);
+ } else {
+ /* just put counter a1 in mode 0 to set its output low */
+ labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 1, I8254_MODE0);
+ }
+
+ /* figure out what method we will use to transfer data */
+ if (labpc_have_dma_chan(dev) &&
+ /* dma unsafe at RT priority,
+ * and too much setup time for CMDF_WAKE_EOS */
+ (cmd->flags & (CMDF_WAKE_EOS | CMDF_PRIORITY)) == 0)
+ xfer = isa_dma_transfer;
+ else if (/* pc-plus has no fifo-half full interrupt */
+ board->is_labpc1200 &&
+ /* wake-end-of-scan should interrupt on fifo not empty */
+ (cmd->flags & CMDF_WAKE_EOS) == 0 &&
+ /* make sure we are taking more than just a few points */
+ (cmd->stop_src != TRIG_COUNT || devpriv->count > 256))
+ xfer = fifo_half_full_transfer;
+ else
+ xfer = fifo_not_empty_transfer;
+ devpriv->current_transfer = xfer;
+
+ labpc_ai_set_chan_and_gain(dev, mode, chan, range, aref);
+
+ labpc_setup_cmd6_reg(dev, s, mode, xfer, range, aref,
+ (cmd->stop_src == TRIG_EXT));
+
+ /* manual says to set scan enable bit on second pass */
+ if (mode == MODE_MULT_CHAN_UP || mode == MODE_MULT_CHAN_DOWN) {
+ devpriv->cmd1 |= CMD1_SCANEN;
+ /* need a brief delay before enabling scan, or scan
+ * list will get screwed when you switch
+ * between scan up to scan down mode - dunno why */
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd1, CMD1_REG);
+ }
+
+ devpriv->write_byte(dev, cmd->chanlist_len, INTERVAL_COUNT_REG);
+ /* load count */
+ devpriv->write_byte(dev, 0x1, INTERVAL_STROBE_REG);
+
+ if (cmd->convert_src == TRIG_TIMER ||
+ cmd->scan_begin_src == TRIG_TIMER) {
+ /* set up pacing */
+ labpc_adc_timing(dev, cmd, mode);
+ /* load counter b0 in mode 3 */
+ labpc_counter_load(dev, 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 */
+ labpc_counter_load(dev, COUNTER_A_BASE_REG,
+ 0, devpriv->divisor_a0, I8254_MODE2);
+ } else {
+ /* initialize pacer counter to prevent any problems */
+ labpc_counter_set_mode(dev, COUNTER_A_BASE_REG, 0, I8254_MODE2);
+ }
+
+ /* set up scan pacing */
+ if (labpc_ai_scan_period(cmd, mode)) {
+ /* load counter b1 in mode 2 */
+ labpc_counter_load(dev, COUNTER_B_BASE_REG,
+ 1, devpriv->divisor_b1, I8254_MODE2);
+ }
+
+ labpc_clear_adc_fifo(dev);
+
+ if (xfer == isa_dma_transfer)
+ labpc_setup_dma(dev, s);
+
+ /* enable error interrupts */
+ devpriv->cmd3 |= CMD3_ERRINTEN;
+ /* enable fifo not empty interrupt? */
+ if (xfer == fifo_not_empty_transfer)
+ devpriv->cmd3 |= CMD3_FIFOINTEN;
+ devpriv->write_byte(dev, devpriv->cmd3, CMD3_REG);
+
+ /* setup any external triggering/pacing (cmd4 register) */
+ devpriv->cmd4 = 0;
+ if (cmd->convert_src != TRIG_EXT)
+ devpriv->cmd4 |= CMD4_ECLKRCV;
+ /* XXX should discard first scan when using interval scanning
+ * since manual says it is not synced with scan clock */
+ if (!labpc_use_continuous_mode(cmd, mode)) {
+ devpriv->cmd4 |= CMD4_INTSCAN;
+ if (cmd->scan_begin_src == TRIG_EXT)
+ devpriv->cmd4 |= CMD4_EOIRCV;
+ }
+ /* single-ended/differential */
+ if (aref == AREF_DIFF)
+ devpriv->cmd4 |= CMD4_SEDIFF;
+ devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG);
+
+ /* startup acquisition */
+
+ spin_lock_irqsave(&dev->spinlock, flags);
+
+ /* use 2 cascaded counters for pacing */
+ devpriv->cmd2 |= CMD2_TBSEL;
+
+ devpriv->cmd2 &= ~(CMD2_SWTRIG | CMD2_HWTRIG | CMD2_PRETRIG);
+ if (cmd->start_src == TRIG_EXT)
+ devpriv->cmd2 |= CMD2_HWTRIG;
+ else
+ devpriv->cmd2 |= CMD2_SWTRIG;
+ if (cmd->stop_src == TRIG_EXT)
+ devpriv->cmd2 |= (CMD2_HWTRIG | CMD2_PRETRIG);
+
+ devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG);
+
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+
+ return 0;
+}
+
+/* read all available samples from ai fifo */
+static int labpc_drain_fifo(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+ struct comedi_async *async = dev->read_subdev->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ unsigned short data;
+ const int timeout = 10000;
+ unsigned int i;
+
+ devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG);
+
+ for (i = 0; (devpriv->stat1 & STAT1_DAVAIL) && i < timeout;
+ i++) {
+ /* quit if we have all the data we want */
+ if (cmd->stop_src == TRIG_COUNT) {
+ if (devpriv->count == 0)
+ break;
+ devpriv->count--;
+ }
+ data = labpc_read_adc_fifo(dev);
+ cfc_write_to_buffer(dev->read_subdev, data);
+ devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG);
+ }
+ if (i == timeout) {
+ dev_err(dev->class_dev, "ai timeout, fifo never empties\n");
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* makes sure all data acquired by board is transferred to comedi (used
+ * when acquisition is terminated by stop_src == TRIG_EXT). */
+static void labpc_drain_dregs(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ if (devpriv->current_transfer == isa_dma_transfer)
+ labpc_drain_dma(dev);
+
+ labpc_drain_fifo(dev);
+}
+
+/* interrupt service routine */
+static irqreturn_t labpc_interrupt(int irq, void *d)
+{
+ struct comedi_device *dev = d;
+ const struct labpc_boardinfo *board = dev->board_ptr;
+ struct labpc_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_async *async;
+ struct comedi_cmd *cmd;
+
+ if (!dev->attached) {
+ dev_err(dev->class_dev, "premature interrupt\n");
+ return IRQ_HANDLED;
+ }
+
+ async = s->async;
+ cmd = &async->cmd;
+
+ /* read board status */
+ devpriv->stat1 = devpriv->read_byte(dev, STAT1_REG);
+ if (board->is_labpc1200)
+ devpriv->stat2 = devpriv->read_byte(dev, STAT2_REG);
+
+ if ((devpriv->stat1 & (STAT1_GATA0 | STAT1_CNTINT | STAT1_OVERFLOW |
+ STAT1_OVERRUN | STAT1_DAVAIL)) == 0 &&
+ (devpriv->stat2 & STAT2_OUTA1) == 0 &&
+ (devpriv->stat2 & STAT2_FIFONHF)) {
+ return IRQ_NONE;
+ }
+
+ if (devpriv->stat1 & STAT1_OVERRUN) {
+ /* clear error interrupt */
+ devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG);
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ cfc_handle_events(dev, s);
+ dev_err(dev->class_dev, "overrun\n");
+ return IRQ_HANDLED;
+ }
+
+ if (devpriv->current_transfer == isa_dma_transfer)
+ labpc_handle_dma_status(dev);
+ else
+ labpc_drain_fifo(dev);
+
+ if (devpriv->stat1 & STAT1_CNTINT) {
+ dev_err(dev->class_dev, "handled timer interrupt?\n");
+ /* clear it */
+ devpriv->write_byte(dev, 0x1, TIMER_CLEAR_REG);
+ }
+
+ if (devpriv->stat1 & STAT1_OVERFLOW) {
+ /* clear error interrupt */
+ devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG);
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ cfc_handle_events(dev, s);
+ dev_err(dev->class_dev, "overflow\n");
+ return IRQ_HANDLED;
+ }
+ /* handle external stop trigger */
+ if (cmd->stop_src == TRIG_EXT) {
+ if (devpriv->stat2 & STAT2_OUTA1) {
+ labpc_drain_dregs(dev);
+ async->events |= COMEDI_CB_EOA;
+ }
+ }
+
+ /* TRIG_COUNT end of acquisition */
+ if (cmd->stop_src == TRIG_COUNT) {
+ if (devpriv->count == 0)
+ async->events |= COMEDI_CB_EOA;
+ }
+
+ cfc_handle_events(dev, s);
+ return IRQ_HANDLED;
+}
+
+static int labpc_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ const struct labpc_boardinfo *board = dev->board_ptr;
+ struct labpc_private *devpriv = dev->private;
+ int channel, range;
+ unsigned long flags;
+ int lsb, msb;
+
+ channel = CR_CHAN(insn->chanspec);
+
+ /* turn off pacing of analog output channel */
+ /* note: hardware bug in daqcard-1200 means pacing cannot
+ * be independently enabled/disabled for its the two channels */
+ spin_lock_irqsave(&dev->spinlock, flags);
+ devpriv->cmd2 &= ~CMD2_LDAC(channel);
+ devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+
+ /* set range */
+ if (board->is_labpc1200) {
+ range = CR_RANGE(insn->chanspec);
+ if (comedi_range_is_unipolar(s, range))
+ devpriv->cmd6 |= CMD6_DACUNI(channel);
+ else
+ devpriv->cmd6 &= ~CMD6_DACUNI(channel);
+ /* write to register */
+ devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG);
+ }
+ /* send data */
+ lsb = data[0] & 0xff;
+ msb = (data[0] >> 8) & 0xff;
+ devpriv->write_byte(dev, lsb, DAC_LSB_REG(channel));
+ devpriv->write_byte(dev, msb, DAC_MSB_REG(channel));
+
+ /* remember value for readback */
+ devpriv->ao_value[channel] = data[0];
+
+ return 1;
+}
+
+static int labpc_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)];
+
+ return 1;
+}
+
+/* lowlevel write to eeprom/dac */
+static void labpc_serial_out(struct comedi_device *dev, unsigned int value,
+ unsigned int value_width)
+{
+ struct labpc_private *devpriv = dev->private;
+ int i;
+
+ for (i = 1; i <= value_width; i++) {
+ /* clear serial clock */
+ devpriv->cmd5 &= ~CMD5_SCLK;
+ /* send bits most significant bit first */
+ if (value & (1 << (value_width - i)))
+ devpriv->cmd5 |= CMD5_SDATA;
+ else
+ devpriv->cmd5 &= ~CMD5_SDATA;
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+ /* set clock to load bit */
+ devpriv->cmd5 |= CMD5_SCLK;
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+ }
+}
+
+/* lowlevel read from eeprom */
+static unsigned int labpc_serial_in(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int value = 0;
+ int i;
+ const int value_width = 8; /* number of bits wide values are */
+
+ for (i = 1; i <= value_width; i++) {
+ /* set serial clock */
+ devpriv->cmd5 |= CMD5_SCLK;
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+ /* clear clock bit */
+ devpriv->cmd5 &= ~CMD5_SCLK;
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+ /* read bits most significant bit first */
+ udelay(1);
+ devpriv->stat2 = devpriv->read_byte(dev, STAT2_REG);
+ if (devpriv->stat2 & STAT2_PROMOUT)
+ value |= 1 << (value_width - i);
+ }
+
+ return value;
+}
+
+static unsigned int labpc_eeprom_read(struct comedi_device *dev,
+ unsigned int address)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int value;
+ /* bits to tell eeprom to expect a read */
+ const int read_instruction = 0x3;
+ /* 8 bit write lengths to eeprom */
+ const int write_length = 8;
+
+ /* enable read/write to eeprom */
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+ devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT);
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+
+ /* send read instruction */
+ labpc_serial_out(dev, read_instruction, write_length);
+ /* send 8 bit address to read from */
+ labpc_serial_out(dev, address, write_length);
+ /* read result */
+ value = labpc_serial_in(dev);
+
+ /* disable read/write to eeprom */
+ devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT);
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+
+ return value;
+}
+
+static unsigned int labpc_eeprom_read_status(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int value;
+ const int read_status_instruction = 0x5;
+ const int write_length = 8; /* 8 bit write lengths to eeprom */
+
+ /* enable read/write to eeprom */
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+ devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT);
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+
+ /* send read status instruction */
+ labpc_serial_out(dev, read_status_instruction, write_length);
+ /* read result */
+ value = labpc_serial_in(dev);
+
+ /* disable read/write to eeprom */
+ devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT);
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+
+ return value;
+}
+
+static int labpc_eeprom_write(struct comedi_device *dev,
+ unsigned int address, unsigned int value)
+{
+ struct labpc_private *devpriv = dev->private;
+ const int write_enable_instruction = 0x6;
+ const int write_instruction = 0x2;
+ const int write_length = 8; /* 8 bit write lengths to eeprom */
+ const int write_in_progress_bit = 0x1;
+ const int timeout = 10000;
+ int i;
+
+ /* make sure there isn't already a write in progress */
+ for (i = 0; i < timeout; i++) {
+ if ((labpc_eeprom_read_status(dev) & write_in_progress_bit) ==
+ 0)
+ break;
+ }
+ if (i == timeout) {
+ dev_err(dev->class_dev, "eeprom write timed out\n");
+ return -ETIME;
+ }
+ /* update software copy of eeprom */
+ devpriv->eeprom_data[address] = value;
+
+ /* enable read/write to eeprom */
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+ devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT);
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+
+ /* send write_enable instruction */
+ labpc_serial_out(dev, write_enable_instruction, write_length);
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+
+ /* send write instruction */
+ devpriv->cmd5 |= CMD5_EEPROMCS;
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+ labpc_serial_out(dev, write_instruction, write_length);
+ /* send 8 bit address to write to */
+ labpc_serial_out(dev, address, write_length);
+ /* write value */
+ labpc_serial_out(dev, value, write_length);
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+
+ /* disable read/write to eeprom */
+ devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT);
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+
+ return 0;
+}
+
+/* writes to 8 bit calibration dacs */
+static void write_caldac(struct comedi_device *dev, unsigned int channel,
+ unsigned int value)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ if (value == devpriv->caldac[channel])
+ return;
+ devpriv->caldac[channel] = value;
+
+ /* clear caldac load bit and make sure we don't write to eeprom */
+ devpriv->cmd5 &= ~(CMD5_CALDACLD | CMD5_EEPROMCS | CMD5_WRTPRT);
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+
+ /* write 4 bit channel */
+ labpc_serial_out(dev, channel, 4);
+ /* write 8 bit caldac value */
+ labpc_serial_out(dev, value, 8);
+
+ /* set and clear caldac bit to load caldac value */
+ devpriv->cmd5 |= CMD5_CALDACLD;
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+ devpriv->cmd5 &= ~CMD5_CALDACLD;
+ udelay(1);
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+}
+
+static int labpc_calib_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+
+ /*
+ * Only write the last data value to the caldac. Preceding
+ * data would be overwritten anyway.
+ */
+ if (insn->n > 0)
+ write_caldac(dev, chan, data[insn->n - 1]);
+
+ return insn->n;
+}
+
+static int labpc_calib_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->caldac[chan];
+
+ return insn->n;
+}
+
+static int labpc_eeprom_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int ret;
+
+ /* only allow writes to user area of eeprom */
+ if (chan < 16 || chan > 127)
+ return -EINVAL;
+
+ /*
+ * Only write the last data value to the eeprom. Preceding
+ * data would be overwritten anyway.
+ */
+ if (insn->n > 0) {
+ ret = labpc_eeprom_write(dev, chan, data[insn->n - 1]);
+ if (ret)
+ return ret;
+ }
+
+ return insn->n;
+}
+
+static int labpc_eeprom_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->eeprom_data[chan];
+
+ return insn->n;
+}
+
+int labpc_common_attach(struct comedi_device *dev,
+ unsigned int irq, unsigned long isr_flags)
+{
+ const struct labpc_boardinfo *board = dev->board_ptr;
+ struct labpc_private *devpriv = dev->private;
+ struct comedi_subdevice *s;
+ int ret;
+ int i;
+
+ if (dev->mmio) {
+ devpriv->read_byte = labpc_readb;
+ devpriv->write_byte = labpc_writeb;
+ } else {
+ devpriv->read_byte = labpc_inb;
+ devpriv->write_byte = labpc_outb;
+ }
+
+ /* initialize board's command registers */
+ devpriv->write_byte(dev, devpriv->cmd1, CMD1_REG);
+ devpriv->write_byte(dev, devpriv->cmd2, CMD2_REG);
+ devpriv->write_byte(dev, devpriv->cmd3, CMD3_REG);
+ devpriv->write_byte(dev, devpriv->cmd4, CMD4_REG);
+ if (board->is_labpc1200) {
+ devpriv->write_byte(dev, devpriv->cmd5, CMD5_REG);
+ devpriv->write_byte(dev, devpriv->cmd6, CMD6_REG);
+ }
+
+ if (irq) {
+ ret = request_irq(irq, labpc_interrupt, isr_flags,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = irq;
+ }
+
+ ret = comedi_alloc_subdevices(dev, 5);
+ if (ret)
+ return ret;
+
+ /* analog input subdevice */
+ s = &dev->subdevices[0];
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF;
+ s->n_chan = 8;
+ s->len_chanlist = 8;
+ s->maxdata = 0x0fff;
+ s->range_table = board->is_labpc1200 ?
+ &range_labpc_1200_ai : &range_labpc_plus_ai;
+ s->insn_read = labpc_ai_insn_read;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->do_cmd = labpc_ai_cmd;
+ s->do_cmdtest = labpc_ai_cmdtest;
+ s->cancel = labpc_cancel;
+ }
+
+ /* analog output */
+ s = &dev->subdevices[1];
+ if (board->has_ao) {
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
+ s->n_chan = NUM_AO_CHAN;
+ s->maxdata = 0x0fff;
+ s->range_table = &range_labpc_ao;
+ s->insn_read = labpc_ao_insn_read;
+ s->insn_write = labpc_ao_insn_write;
+
+ /* initialize analog outputs to a known value */
+ for (i = 0; i < s->n_chan; i++) {
+ short lsb, msb;
+
+ devpriv->ao_value[i] = s->maxdata / 2;
+ lsb = devpriv->ao_value[i] & 0xff;
+ msb = (devpriv->ao_value[i] >> 8) & 0xff;
+ devpriv->write_byte(dev, lsb, DAC_LSB_REG(i));
+ devpriv->write_byte(dev, msb, DAC_MSB_REG(i));
+ }
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ /* 8255 dio */
+ s = &dev->subdevices[2];
+ if (dev->mmio)
+ ret = subdev_8255_mm_init(dev, s, NULL, DIO_BASE_REG);
+ else
+ ret = subdev_8255_init(dev, s, NULL, DIO_BASE_REG);
+ if (ret)
+ return ret;
+
+ /* calibration subdevices for boards that have one */
+ s = &dev->subdevices[3];
+ if (board->is_labpc1200) {
+ s->type = COMEDI_SUBD_CALIB;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = 16;
+ s->maxdata = 0xff;
+ s->insn_read = labpc_calib_insn_read;
+ s->insn_write = labpc_calib_insn_write;
+
+ for (i = 0; i < s->n_chan; i++)
+ write_caldac(dev, i, s->maxdata / 2);
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ /* EEPROM */
+ s = &dev->subdevices[4];
+ if (board->is_labpc1200) {
+ s->type = COMEDI_SUBD_MEMORY;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = EEPROM_SIZE;
+ s->maxdata = 0xff;
+ s->insn_read = labpc_eeprom_insn_read;
+ s->insn_write = labpc_eeprom_insn_write;
+
+ for (i = 0; i < s->n_chan; i++)
+ devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(labpc_common_attach);
+
+static int __init labpc_common_init(void)
+{
+ return 0;
+}
+module_init(labpc_common_init);
+
+static void __exit labpc_common_exit(void)
+{
+}
+module_exit(labpc_common_exit);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi helper for ni_labpc, ni_labpc_pci, ni_labpc_cs");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.c b/drivers/staging/comedi/drivers/ni_labpc_isadma.c
index cb7d1c952cf2..967202e0635e 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_isadma.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.c
@@ -152,7 +152,7 @@ static void handle_isa_dma(struct comedi_device *dev)
void labpc_handle_dma_status(struct comedi_device *dev)
{
- const struct labpc_boardinfo *board = comedi_board(dev);
+ const struct labpc_boardinfo *board = dev->board_ptr;
struct labpc_private *devpriv = dev->private;
/*
diff --git a/drivers/staging/comedi/drivers/ni_labpc_pci.c b/drivers/staging/comedi/drivers/ni_labpc_pci.c
index 65984ea0a3ee..3fc420406564 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_pci.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_pci.c
@@ -108,20 +108,11 @@ static int labpc_pci_auto_attach(struct comedi_device *dev,
return labpc_common_attach(dev, pcidev->irq, IRQF_SHARED);
}
-static void labpc_pci_detach(struct comedi_device *dev)
-{
- if (dev->mmio)
- iounmap(dev->mmio);
- if (dev->irq)
- free_irq(dev->irq, dev);
- comedi_pci_disable(dev);
-}
-
static struct comedi_driver labpc_pci_comedi_driver = {
.driver_name = "labpc_pci",
.module = THIS_MODULE,
.auto_attach = labpc_pci_auto_attach,
- .detach = labpc_pci_detach,
+ .detach = comedi_pci_detach,
};
static const struct pci_device_id labpc_pci_table[] = {
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index 297c95d2e0a3..320b080149b6 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -1186,7 +1186,7 @@ static void ni_ao_fifo_load(struct comedi_device *dev,
static int ni_ao_fifo_half_empty(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
int n;
n = comedi_buf_read_n_available(s);
@@ -1209,7 +1209,7 @@ static int ni_ao_fifo_half_empty(struct comedi_device *dev,
static int ni_ao_prep_fifo(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
int n;
@@ -1296,7 +1296,7 @@ static void ni_ai_fifo_read(struct comedi_device *dev,
static void ni_handle_fifo_half_full(struct comedi_device *dev)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
struct comedi_subdevice *s = dev->read_subdev;
int n;
@@ -1881,7 +1881,7 @@ static void ni_m_series_load_channelgain_list(struct comedi_device *dev,
unsigned int n_chan,
unsigned int *list)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
unsigned int chan, range, aref;
unsigned int i;
@@ -1988,7 +1988,7 @@ static void ni_load_channelgain_list(struct comedi_device *dev,
struct comedi_subdevice *s,
unsigned int n_chan, unsigned int *list)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
unsigned int offset = (s->maxdata + 1) >> 1;
unsigned int chan, range, aref;
@@ -2108,7 +2108,7 @@ static int ni_ai_insn_read(struct comedi_device *dev,
unsigned int mask = (s->maxdata + 1) >> 1;
int i, n;
unsigned signbits;
- unsigned short d;
+ unsigned int d;
unsigned long dl;
ni_load_channelgain_list(dev, s, 1, &insn->chanspec);
@@ -2206,15 +2206,15 @@ static int ni_ns_to_timer(const struct comedi_device *dev, unsigned nanosec,
struct ni_private *devpriv = dev->private;
int divider;
- switch (flags & TRIG_ROUND_MASK) {
- case TRIG_ROUND_NEAREST:
+ switch (flags & CMDF_ROUND_MASK) {
+ case CMDF_ROUND_NEAREST:
default:
divider = (nanosec + devpriv->clock_ns / 2) / devpriv->clock_ns;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
divider = (nanosec) / devpriv->clock_ns;
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
divider = (nanosec + devpriv->clock_ns - 1) / devpriv->clock_ns;
break;
}
@@ -2231,7 +2231,7 @@ static unsigned ni_timer_to_ns(const struct comedi_device *dev, int timer)
static unsigned ni_min_ai_scan_period_ns(struct comedi_device *dev,
unsigned num_channels)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
/* simultaneously-sampled inputs */
@@ -2245,7 +2245,7 @@ static unsigned ni_min_ai_scan_period_ns(struct comedi_device *dev,
static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
int err = 0;
unsigned int tmp;
@@ -2541,7 +2541,7 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* load SI */
timer = ni_ns_to_timer(dev, cmd->scan_begin_arg,
- TRIG_ROUND_NEAREST);
+ CMDF_ROUND_NEAREST);
ni_stc_writel(dev, timer, AI_SI_Load_A_Registers);
ni_stc_writew(dev, AI_SI_Load, AI_Command_1_Register);
break;
@@ -2569,7 +2569,7 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
timer = 1;
else
timer = ni_ns_to_timer(dev, cmd->convert_arg,
- TRIG_ROUND_NEAREST);
+ CMDF_ROUND_NEAREST);
/* 0,0 does not work */
ni_stc_writew(dev, 1, AI_SI2_Load_A_Register);
ni_stc_writew(dev, timer, AI_SI2_Load_B_Register);
@@ -2610,7 +2610,7 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
interrupt_a_enable |= AI_FIFO_Interrupt_Enable;
#endif
- if (cmd->flags & TRIG_WAKE_EOS
+ if (cmd->flags & CMDF_WAKE_EOS
|| (devpriv->ai_cmd2 & AI_End_On_End_Of_Scan)) {
/* wake on end-of-scan */
devpriv->aimode = AIMODE_SCAN;
@@ -2732,9 +2732,6 @@ static int ni_ai_insn_config(struct comedi_device *dev,
calib_source = data[1] & 0xf;
- if (calib_source > 0xF)
- return -EINVAL;
-
devpriv->ai_calib_source = calib_source;
ni_writew(dev, calib_source, Calibration_Channel_6143);
} else {
@@ -2921,21 +2918,6 @@ static int ni_ao_config_chanlist(struct comedi_device *dev,
return ni_old_ao_config_chanlist(dev, s, chanspec, n_chans);
}
-static int ni_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct ni_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int i;
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao[chan];
-
- return insn->n;
-}
-
static int ni_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -2962,7 +2944,7 @@ static int ni_ao_insn_write(struct comedi_device *dev,
for (i = 0; i < insn->n; i++) {
unsigned int val = data[i];
- devpriv->ao[chan] = val;
+ s->readback[chan] = val;
if (devpriv->is_6xxx) {
/*
@@ -2997,7 +2979,7 @@ static int ni_ao_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
switch (data[0]) {
@@ -3098,7 +3080,7 @@ static int ni_ao_inttrig(struct comedi_device *dev,
static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
const struct comedi_cmd *cmd = &s->async->cmd;
int bits;
@@ -3208,7 +3190,7 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ao_cmd2 &= ~AO_BC_Gate_Enable;
trigvar =
ni_ns_to_timer(dev, cmd->scan_begin_arg,
- TRIG_ROUND_NEAREST);
+ CMDF_ROUND_NEAREST);
ni_stc_writel(dev, 1, AO_UI_Load_A_Register);
ni_stc_writew(dev, AO_UI_Load, AO_Command_1_Register);
ni_stc_writel(dev, trigvar, AO_UI_Load_A_Register);
@@ -3299,7 +3281,7 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
int err = 0;
unsigned int tmp;
@@ -3552,12 +3534,10 @@ static int ni_cdio_cmdtest(struct comedi_device *dev,
if (err)
return 3;
- /* step 4: fix up any arguments */
-
- if (err)
- return 4;
+ /* Step 4: fix up any arguments */
/* Step 5: check channel list if it exists */
+
if (cmd->chanlist && cmd->chanlist_len > 0)
err |= ni_cdio_check_chanlist(dev, s, cmd);
@@ -4176,16 +4156,15 @@ static int ni_freq_out_insn_config(struct comedi_device *dev,
return insn->n;
}
-static int ni_8255_callback(int dir, int port, int data, unsigned long arg)
+static int ni_8255_callback(struct comedi_device *dev,
+ int dir, int port, int data, unsigned long iobase)
{
- struct comedi_device *dev = (struct comedi_device *)arg;
-
if (dir) {
- ni_writeb(dev, data, Port_A + 2 * port);
+ ni_writeb(dev, data, iobase + 2 * port);
return 0;
}
- return ni_readb(dev, Port_A + 2 * port);
+ return ni_readb(dev, iobase + 2 * port);
}
static int ni_get_pwm_config(struct comedi_device *dev, unsigned int *data)
@@ -4208,15 +4187,15 @@ static int ni_m_series_pwm_config(struct comedi_device *dev,
switch (data[0]) {
case INSN_CONFIG_PWM_OUTPUT:
switch (data[1]) {
- case TRIG_ROUND_NEAREST:
+ case CMDF_ROUND_NEAREST:
up_count =
(data[2] +
devpriv->clock_ns / 2) / devpriv->clock_ns;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
up_count = data[2] / devpriv->clock_ns;
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
up_count =
(data[2] + devpriv->clock_ns -
1) / devpriv->clock_ns;
@@ -4225,15 +4204,15 @@ static int ni_m_series_pwm_config(struct comedi_device *dev,
return -EINVAL;
}
switch (data[3]) {
- case TRIG_ROUND_NEAREST:
+ case CMDF_ROUND_NEAREST:
down_count =
(data[4] +
devpriv->clock_ns / 2) / devpriv->clock_ns;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
down_count = data[4] / devpriv->clock_ns;
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
down_count =
(data[4] + devpriv->clock_ns -
1) / devpriv->clock_ns;
@@ -4272,15 +4251,15 @@ static int ni_6143_pwm_config(struct comedi_device *dev,
switch (data[0]) {
case INSN_CONFIG_PWM_OUTPUT:
switch (data[1]) {
- case TRIG_ROUND_NEAREST:
+ case CMDF_ROUND_NEAREST:
up_count =
(data[2] +
devpriv->clock_ns / 2) / devpriv->clock_ns;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
up_count = data[2] / devpriv->clock_ns;
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
up_count =
(data[2] + devpriv->clock_ns -
1) / devpriv->clock_ns;
@@ -4289,15 +4268,15 @@ static int ni_6143_pwm_config(struct comedi_device *dev,
return -EINVAL;
}
switch (data[3]) {
- case TRIG_ROUND_NEAREST:
+ case CMDF_ROUND_NEAREST:
down_count =
(data[4] +
devpriv->clock_ns / 2) / devpriv->clock_ns;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
down_count = data[4] / devpriv->clock_ns;
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
down_count =
(data[4] + devpriv->clock_ns -
1) / devpriv->clock_ns;
@@ -4390,7 +4369,7 @@ static struct caldac_struct caldacs[] = {
static void ni_write_caldac(struct comedi_device *dev, int addr, int val)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
unsigned int loadbit = 0, bits = 0, bit, bitstring = 0;
int i;
@@ -4448,7 +4427,7 @@ static int ni_calib_insn_read(struct comedi_device *dev,
static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
int i, j;
int n_dacs;
@@ -5418,7 +5397,7 @@ static int ni_alloc_private(struct comedi_device *dev)
static int ni_E_init(struct comedi_device *dev,
unsigned interrupt_pin, unsigned irq_polarity)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
struct comedi_subdevice *s;
int ret;
@@ -5491,9 +5470,13 @@ static int ni_E_init(struct comedi_device *dev,
s->n_chan = board->n_aochan;
s->maxdata = board->ao_maxdata;
s->range_table = board->ao_range_table;
- s->insn_read = ni_ao_insn_read;
- s->insn_write = ni_ao_insn_write;
s->insn_config = ni_ao_insn_config;
+ s->insn_write = ni_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
/*
* Along with the IRQ we need either a FIFO or DMA for
@@ -5560,8 +5543,7 @@ static int ni_E_init(struct comedi_device *dev,
/* 8255 device */
s = &dev->subdevices[NI_8255_DIO_SUBDEV];
if (board->has_8255) {
- ret = subdev_8255_init(dev, s, ni_8255_callback,
- (unsigned long)dev);
+ ret = subdev_8255_init(dev, s, ni_8255_callback, Port_A);
if (ret)
return ret;
} else {
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index b5b36af80205..5252cba82e5e 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -530,15 +530,15 @@ static int ni_pcidio_ns_to_timer(int *nanosec, unsigned int flags)
base = TIMER_BASE;
- switch (flags & TRIG_ROUND_MASK) {
- case TRIG_ROUND_NEAREST:
+ switch (flags & CMDF_ROUND_MASK) {
+ case CMDF_ROUND_NEAREST:
default:
divider = (*nanosec + base / 2) / base;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
divider = (*nanosec) / base;
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
divider = (*nanosec + base - 1) / base;
break;
}
@@ -598,11 +598,10 @@ static int ni_pcidio_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_COUNT) {
- /* no limit */
- } else { /* TRIG_NONE */
+ 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;
@@ -669,7 +668,7 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
writeb(3, dev->mmio + LinePolarities);
writeb(0xc0, dev->mmio + AckSer);
writel(ni_pcidio_ns_to_timer(&cmd->scan_begin_arg,
- TRIG_ROUND_NEAREST),
+ CMDF_ROUND_NEAREST),
dev->mmio + StartDelay);
writeb(1, dev->mmio + ReqDelay);
writeb(1, dev->mmio + ReqNotDelay);
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index da61fa70decf..3b2bdebbca59 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -1082,7 +1082,7 @@ static void m_series_init_eeprom_buffer(struct comedi_device *dev)
static void init_6143(struct comedi_device *dev)
{
- const struct ni_board_struct *board = comedi_board(dev);
+ const struct ni_board_struct *board = dev->board_ptr;
struct ni_private *devpriv = dev->private;
/* Disable interrupts */
diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/staging/comedi/drivers/ni_stc.h
index a2841292ddd4..29efce30eb7f 100644
--- a/drivers/staging/comedi/drivers/ni_stc.h
+++ b/drivers/staging/comedi/drivers/ni_stc.h
@@ -1423,7 +1423,6 @@ struct ni_private {
unsigned int changain_spec;
unsigned int caldac_maxdata_list[MAX_N_CALDACS];
- unsigned short ao[MAX_N_AO_CHAN];
unsigned short caldacs[MAX_N_CALDACS];
unsigned short ai_cmd2;
diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c
index 299ceddfb233..26e7291c4a51 100644
--- a/drivers/staging/comedi/drivers/ni_tiocmd.c
+++ b/drivers/staging/comedi/drivers/ni_tiocmd.c
@@ -185,7 +185,7 @@ static int ni_tio_cmd_setup(struct comedi_subdevice *s)
}
if (set_gate_source)
retval = ni_tio_set_gate_src(counter, 0, gate_source);
- if (cmd->flags & TRIG_WAKE_EOS) {
+ if (cmd->flags & CMDF_WAKE_EOS) {
ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx),
GI_GATE_INTERRUPT_ENABLE(cidx),
GI_GATE_INTERRUPT_ENABLE(cidx));
@@ -286,10 +286,9 @@ int ni_tio_cmdtest(struct comedi_device *dev,
if (err)
return 3;
- /* step 4: fix up any arguments */
+ /* Step 4: fix up any arguments */
- if (err)
- return 4;
+ /* Step 5: check channel list if it exists */
return 0;
}
diff --git a/drivers/staging/comedi/drivers/ni_usb6501.c b/drivers/staging/comedi/drivers/ni_usb6501.c
new file mode 100644
index 000000000000..df7ada8611f4
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_usb6501.c
@@ -0,0 +1,621 @@
+/*
+ * comedi/drivers/ni_usb6501.c
+ * Comedi driver for National Instruments USB-6501
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2014 Luca Ellero <luca.ellero@brickedbrain.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.
+ */
+
+/*
+ * Driver: ni_usb6501
+ * Description: National Instruments USB-6501 module
+ * Devices: [National Instruments] USB-6501 (ni_usb6501)
+ * Author: Luca Ellero <luca.ellero@brickedbrain.com>
+ * Updated: 8 Sep 2014
+ * Status: works
+ *
+ *
+ * Configuration Options:
+ * none
+ */
+
+/*
+ * NI-6501 - USB PROTOCOL DESCRIPTION
+ *
+ * Every command is composed by two USB packets:
+ * - request (out)
+ * - response (in)
+ *
+ * Every packet is at least 12 bytes long, here is the meaning of
+ * every field (all values are hex):
+ *
+ * byte 0 is always 00
+ * byte 1 is always 01
+ * byte 2 is always 00
+ * byte 3 is the total packet length
+ *
+ * byte 4 is always 00
+ * byte 5 is is the total packet length - 4
+ * byte 6 is always 01
+ * byte 7 is the command
+ *
+ * byte 8 is 02 (request) or 00 (response)
+ * byte 9 is 00 (response) or 10 (port request) or 20 (counter request)
+ * byte 10 is always 00
+ * byte 11 is 00 (request) or 02 (response)
+ *
+ * PORT PACKETS
+ *
+ * CMD: 0xE READ_PORT
+ * REQ: 00 01 00 10 00 0C 01 0E 02 10 00 00 00 03 <PORT> 00
+ * RES: 00 01 00 10 00 0C 01 00 00 00 00 02 00 03 <BMAP> 00
+ *
+ * CMD: 0xF WRITE_PORT
+ * REQ: 00 01 00 14 00 10 01 0F 02 10 00 00 00 03 <PORT> 00 03 <BMAP> 00 00
+ * RES: 00 01 00 0C 00 08 01 00 00 00 00 02
+ *
+ * CMD: 0x12 SET_PORT_DIR (0 = input, 1 = output)
+ * REQ: 00 01 00 18 00 14 01 12 02 10 00 00
+ * 00 05 <PORT 0> <PORT 1> <PORT 2> 00 05 00 00 00 00 00
+ * RES: 00 01 00 0C 00 08 01 00 00 00 00 02
+ *
+ * COUNTER PACKETS
+ *
+ * CMD 0x9: START_COUNTER
+ * REQ: 00 01 00 0C 00 08 01 09 02 20 00 00
+ * RES: 00 01 00 0C 00 08 01 00 00 00 00 02
+ *
+ * CMD 0xC: STOP_COUNTER
+ * REQ: 00 01 00 0C 00 08 01 0C 02 20 00 00
+ * RES: 00 01 00 0C 00 08 01 00 00 00 00 02
+ *
+ * CMD 0xE: READ_COUNTER
+ * REQ: 00 01 00 0C 00 08 01 0E 02 20 00 00
+ * RES: 00 01 00 10 00 0C 01 00 00 00 00 02 <u32 counter value, Big Endian>
+ *
+ * CMD 0xF: WRITE_COUNTER
+ * REQ: 00 01 00 10 00 0C 01 0F 02 20 00 00 <u32 counter value, Big Endian>
+ * RES: 00 01 00 0C 00 08 01 00 00 00 00 02
+ *
+ *
+ * Please visit http://www.brickedbrain.com if you need
+ * additional information or have any questions.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "../comedidev.h"
+
+#define NI6501_TIMEOUT 1000
+
+/* Port request packets */
+static const u8 READ_PORT_REQUEST[] = {0x00, 0x01, 0x00, 0x10,
+ 0x00, 0x0C, 0x01, 0x0E,
+ 0x02, 0x10, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x00};
+
+static const u8 WRITE_PORT_REQUEST[] = {0x00, 0x01, 0x00, 0x14,
+ 0x00, 0x10, 0x01, 0x0F,
+ 0x02, 0x10, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00};
+
+static const u8 SET_PORT_DIR_REQUEST[] = {0x00, 0x01, 0x00, 0x18,
+ 0x00, 0x14, 0x01, 0x12,
+ 0x02, 0x10, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+/* Counter request packets */
+static const u8 START_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x0C,
+ 0x00, 0x08, 0x01, 0x09,
+ 0x02, 0x20, 0x00, 0x00};
+
+static const u8 STOP_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x0C,
+ 0x00, 0x08, 0x01, 0x0C,
+ 0x02, 0x20, 0x00, 0x00};
+
+static const u8 READ_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x0C,
+ 0x00, 0x08, 0x01, 0x0E,
+ 0x02, 0x20, 0x00, 0x00};
+
+static const u8 WRITE_COUNTER_REQUEST[] = {0x00, 0x01, 0x00, 0x10,
+ 0x00, 0x0C, 0x01, 0x0F,
+ 0x02, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+/* Response packets */
+static const u8 GENERIC_RESPONSE[] = {0x00, 0x01, 0x00, 0x0C,
+ 0x00, 0x08, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x02};
+
+static const u8 READ_PORT_RESPONSE[] = {0x00, 0x01, 0x00, 0x10,
+ 0x00, 0x0C, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x03, 0x00, 0x00};
+
+static const u8 READ_COUNTER_RESPONSE[] = {0x00, 0x01, 0x00, 0x10,
+ 0x00, 0x0C, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00};
+
+enum commands {
+ READ_PORT,
+ WRITE_PORT,
+ SET_PORT_DIR,
+ START_COUNTER,
+ STOP_COUNTER,
+ READ_COUNTER,
+ WRITE_COUNTER
+};
+
+struct ni6501_private {
+ struct usb_endpoint_descriptor *ep_rx;
+ struct usb_endpoint_descriptor *ep_tx;
+ struct semaphore sem;
+ u8 *usb_rx_buf;
+ u8 *usb_tx_buf;
+};
+
+static int ni6501_port_command(struct comedi_device *dev, int command,
+ const u8 *port, u8 *bitmap)
+{
+ struct usb_device *usb = comedi_to_usb_dev(dev);
+ struct ni6501_private *devpriv = dev->private;
+ int request_size, response_size;
+ u8 *tx = devpriv->usb_tx_buf;
+ int ret;
+
+ if (command != SET_PORT_DIR && !bitmap)
+ return -EINVAL;
+
+ down(&devpriv->sem);
+
+ switch (command) {
+ case READ_PORT:
+ request_size = sizeof(READ_PORT_REQUEST);
+ response_size = sizeof(READ_PORT_RESPONSE);
+ memcpy(tx, READ_PORT_REQUEST, request_size);
+ tx[14] = port[0];
+ break;
+ case WRITE_PORT:
+ request_size = sizeof(WRITE_PORT_REQUEST);
+ response_size = sizeof(GENERIC_RESPONSE);
+ memcpy(tx, WRITE_PORT_REQUEST, request_size);
+ tx[14] = port[0];
+ tx[17] = bitmap[0];
+ break;
+ case SET_PORT_DIR:
+ request_size = sizeof(SET_PORT_DIR_REQUEST);
+ response_size = sizeof(GENERIC_RESPONSE);
+ memcpy(tx, SET_PORT_DIR_REQUEST, request_size);
+ tx[14] = port[0];
+ tx[15] = port[1];
+ tx[16] = port[2];
+ break;
+ default:
+ ret = -EINVAL;
+ goto end;
+ }
+
+ ret = usb_bulk_msg(usb,
+ usb_sndbulkpipe(usb,
+ devpriv->ep_tx->bEndpointAddress),
+ devpriv->usb_tx_buf,
+ request_size,
+ NULL,
+ NI6501_TIMEOUT);
+ if (ret)
+ goto end;
+
+ ret = usb_bulk_msg(usb,
+ usb_rcvbulkpipe(usb,
+ devpriv->ep_rx->bEndpointAddress),
+ devpriv->usb_rx_buf,
+ response_size,
+ NULL,
+ NI6501_TIMEOUT);
+ if (ret)
+ goto end;
+
+ /* Check if results are valid */
+
+ if (command == READ_PORT) {
+ bitmap[0] = devpriv->usb_rx_buf[14];
+ /* mask bitmap for comparing */
+ devpriv->usb_rx_buf[14] = 0x00;
+
+ if (memcmp(devpriv->usb_rx_buf, READ_PORT_RESPONSE,
+ sizeof(READ_PORT_RESPONSE))) {
+ ret = -EINVAL;
+ }
+ } else if (memcmp(devpriv->usb_rx_buf, GENERIC_RESPONSE,
+ sizeof(GENERIC_RESPONSE))) {
+ ret = -EINVAL;
+ }
+end:
+ up(&devpriv->sem);
+
+ return ret;
+}
+
+static int ni6501_counter_command(struct comedi_device *dev, int command,
+ u32 *val)
+{
+ struct usb_device *usb = comedi_to_usb_dev(dev);
+ struct ni6501_private *devpriv = dev->private;
+ int request_size, response_size;
+ u8 *tx = devpriv->usb_tx_buf;
+ int ret;
+
+ if ((command == READ_COUNTER || command == WRITE_COUNTER) && !val)
+ return -EINVAL;
+
+ down(&devpriv->sem);
+
+ switch (command) {
+ case START_COUNTER:
+ request_size = sizeof(START_COUNTER_REQUEST);
+ response_size = sizeof(GENERIC_RESPONSE);
+ memcpy(tx, START_COUNTER_REQUEST, request_size);
+ break;
+ case STOP_COUNTER:
+ request_size = sizeof(STOP_COUNTER_REQUEST);
+ response_size = sizeof(GENERIC_RESPONSE);
+ memcpy(tx, STOP_COUNTER_REQUEST, request_size);
+ break;
+ case READ_COUNTER:
+ request_size = sizeof(READ_COUNTER_REQUEST);
+ response_size = sizeof(READ_COUNTER_RESPONSE);
+ memcpy(tx, READ_COUNTER_REQUEST, request_size);
+ break;
+ case WRITE_COUNTER:
+ request_size = sizeof(WRITE_COUNTER_REQUEST);
+ response_size = sizeof(GENERIC_RESPONSE);
+ memcpy(tx, WRITE_COUNTER_REQUEST, request_size);
+ /* Setup tx packet: bytes 12,13,14,15 hold the */
+ /* u32 counter value (Big Endian) */
+ *((__be32 *)&tx[12]) = cpu_to_be32(*val);
+ break;
+ default:
+ ret = -EINVAL;
+ goto end;
+ }
+
+ ret = usb_bulk_msg(usb,
+ usb_sndbulkpipe(usb,
+ devpriv->ep_tx->bEndpointAddress),
+ devpriv->usb_tx_buf,
+ request_size,
+ NULL,
+ NI6501_TIMEOUT);
+ if (ret)
+ goto end;
+
+ ret = usb_bulk_msg(usb,
+ usb_rcvbulkpipe(usb,
+ devpriv->ep_rx->bEndpointAddress),
+ devpriv->usb_rx_buf,
+ response_size,
+ NULL,
+ NI6501_TIMEOUT);
+ if (ret)
+ goto end;
+
+ /* Check if results are valid */
+
+ if (command == READ_COUNTER) {
+ int i;
+
+ /* Read counter value: bytes 12,13,14,15 of rx packet */
+ /* hold the u32 counter value (Big Endian) */
+ *val = be32_to_cpu(*((__be32 *)&devpriv->usb_rx_buf[12]));
+
+ /* mask counter value for comparing */
+ for (i = 12; i < sizeof(READ_COUNTER_RESPONSE); ++i)
+ devpriv->usb_rx_buf[i] = 0x00;
+
+ if (memcmp(devpriv->usb_rx_buf, READ_COUNTER_RESPONSE,
+ sizeof(READ_COUNTER_RESPONSE))) {
+ ret = -EINVAL;
+ }
+ } else if (memcmp(devpriv->usb_rx_buf, GENERIC_RESPONSE,
+ sizeof(GENERIC_RESPONSE))) {
+ ret = -EINVAL;
+ }
+end:
+ up(&devpriv->sem);
+
+ return ret;
+}
+
+static int ni6501_dio_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ int ret;
+ u8 port[3];
+
+ ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+ if (ret)
+ return ret;
+
+ port[0] = (s->io_bits) & 0xff;
+ port[1] = (s->io_bits >> 8) & 0xff;
+ port[2] = (s->io_bits >> 16) & 0xff;
+
+ ret = ni6501_port_command(dev, SET_PORT_DIR, port, NULL);
+ if (ret)
+ return ret;
+
+ return insn->n;
+}
+
+static int ni6501_dio_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int mask;
+ int ret;
+ u8 port;
+ u8 bitmap;
+
+ mask = comedi_dio_update_state(s, data);
+
+ for (port = 0; port < 3; port++) {
+ if (mask & (0xFF << port * 8)) {
+ bitmap = (s->state >> port * 8) & 0xFF;
+ ret = ni6501_port_command(dev, WRITE_PORT,
+ &port, &bitmap);
+ if (ret)
+ return ret;
+ }
+ }
+
+ data[1] = 0;
+
+ for (port = 0; port < 3; port++) {
+ ret = ni6501_port_command(dev, READ_PORT, &port, &bitmap);
+ if (ret)
+ return ret;
+ data[1] |= bitmap << port * 8;
+ }
+
+ return insn->n;
+}
+
+static int ni6501_cnt_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ int ret;
+ u32 val = 0;
+
+ switch (data[0]) {
+ case INSN_CONFIG_ARM:
+ ret = ni6501_counter_command(dev, START_COUNTER, NULL);
+ break;
+ case INSN_CONFIG_DISARM:
+ ret = ni6501_counter_command(dev, STOP_COUNTER, NULL);
+ break;
+ case INSN_CONFIG_RESET:
+ ret = ni6501_counter_command(dev, STOP_COUNTER, NULL);
+ if (ret)
+ break;
+ ret = ni6501_counter_command(dev, WRITE_COUNTER, &val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret ? ret : insn->n;
+}
+
+static int ni6501_cnt_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ int ret;
+ u32 val;
+ unsigned int i;
+
+ for (i = 0; i < insn->n; i++) {
+ ret = ni6501_counter_command(dev, READ_COUNTER, &val);
+ if (ret)
+ return ret;
+ data[i] = val;
+ }
+
+ return insn->n;
+}
+
+static int ni6501_cnt_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ int ret;
+
+ if (insn->n) {
+ u32 val = data[insn->n - 1];
+
+ ret = ni6501_counter_command(dev, WRITE_COUNTER, &val);
+ if (ret)
+ return ret;
+ }
+
+ return insn->n;
+}
+
+static int ni6501_alloc_usb_buffers(struct comedi_device *dev)
+{
+ struct ni6501_private *devpriv = dev->private;
+ size_t size;
+
+ size = le16_to_cpu(devpriv->ep_rx->wMaxPacketSize);
+ devpriv->usb_rx_buf = kzalloc(size, GFP_KERNEL);
+ if (!devpriv->usb_rx_buf)
+ return -ENOMEM;
+
+ size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize);
+ devpriv->usb_tx_buf = kzalloc(size, GFP_KERNEL);
+ if (!devpriv->usb_tx_buf) {
+ kfree(devpriv->usb_rx_buf);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int ni6501_find_endpoints(struct comedi_device *dev)
+{
+ struct usb_interface *intf = comedi_to_usb_interface(dev);
+ struct ni6501_private *devpriv = dev->private;
+ struct usb_host_interface *iface_desc = intf->cur_altsetting;
+ struct usb_endpoint_descriptor *ep_desc;
+ int i;
+
+ if (iface_desc->desc.bNumEndpoints != 2) {
+ dev_err(dev->class_dev, "Wrong number of endpoints\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+ ep_desc = &iface_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_bulk_in(ep_desc)) {
+ if (!devpriv->ep_rx)
+ devpriv->ep_rx = ep_desc;
+ continue;
+ }
+
+ if (usb_endpoint_is_bulk_out(ep_desc)) {
+ if (!devpriv->ep_tx)
+ devpriv->ep_tx = ep_desc;
+ continue;
+ }
+ }
+
+ if (!devpriv->ep_rx || !devpriv->ep_tx)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int ni6501_auto_attach(struct comedi_device *dev,
+ unsigned long context)
+{
+ struct usb_interface *intf = comedi_to_usb_interface(dev);
+ struct ni6501_private *devpriv;
+ struct comedi_subdevice *s;
+ int ret;
+
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+ if (!devpriv)
+ return -ENOMEM;
+
+ ret = ni6501_find_endpoints(dev);
+ if (ret)
+ return ret;
+
+ ret = ni6501_alloc_usb_buffers(dev);
+ if (ret)
+ return ret;
+
+ sema_init(&devpriv->sem, 1);
+ usb_set_intfdata(intf, devpriv);
+
+ ret = comedi_alloc_subdevices(dev, 2);
+ if (ret)
+ return ret;
+
+ /* Digital Input/Output subdevice */
+ s = &dev->subdevices[0];
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 24;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = ni6501_dio_insn_bits;
+ s->insn_config = ni6501_dio_insn_config;
+
+ /* Counter subdevice */
+ s = &dev->subdevices[1];
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL;
+ s->n_chan = 1;
+ s->maxdata = 0xffffffff;
+ s->insn_read = ni6501_cnt_insn_read;
+ s->insn_write = ni6501_cnt_insn_write;
+ s->insn_config = ni6501_cnt_insn_config;
+
+ return 0;
+}
+
+static void ni6501_detach(struct comedi_device *dev)
+{
+ struct usb_interface *intf = comedi_to_usb_interface(dev);
+ struct ni6501_private *devpriv = dev->private;
+
+ if (!devpriv)
+ return;
+
+ down(&devpriv->sem);
+
+ usb_set_intfdata(intf, NULL);
+
+ kfree(devpriv->usb_rx_buf);
+ kfree(devpriv->usb_tx_buf);
+
+ up(&devpriv->sem);
+}
+
+static struct comedi_driver ni6501_driver = {
+ .module = THIS_MODULE,
+ .driver_name = "ni6501",
+ .auto_attach = ni6501_auto_attach,
+ .detach = ni6501_detach,
+};
+
+static int ni6501_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return comedi_usb_auto_config(intf, &ni6501_driver, id->driver_info);
+}
+
+static const struct usb_device_id ni6501_usb_table[] = {
+ { USB_DEVICE(0x3923, 0x718a) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, ni6501_usb_table);
+
+static struct usb_driver ni6501_usb_driver = {
+ .name = "ni6501",
+ .id_table = ni6501_usb_table,
+ .probe = ni6501_usb_probe,
+ .disconnect = comedi_usb_auto_unconfig,
+};
+module_comedi_usb_driver(ni6501_driver, ni6501_usb_driver);
+
+MODULE_AUTHOR("Luca Ellero");
+MODULE_DESCRIPTION("Comedi driver for National Instruments USB-6501");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index 40f9136f0bb6..47f4887108a7 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -157,7 +157,6 @@ static const struct pcl711_board boardtypes[] = {
struct pcl711_private {
unsigned int ntrig;
- unsigned int ao_readback[2];
unsigned int divisor1;
unsigned int divisor2;
};
@@ -335,7 +334,9 @@ 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_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)
@@ -377,15 +378,8 @@ static int pcl711_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
pcl711_set_changain(dev, s, cmd->chanlist[0]);
- if (cmd->stop_src == TRIG_COUNT) {
- if (cmd->stop_arg == 0) {
- /* an empty acquisition */
- s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
- return 0;
- }
+ if (cmd->stop_src == TRIG_COUNT)
devpriv->ntrig = cmd->stop_arg;
- }
if (cmd->scan_begin_src == TRIG_TIMER) {
pcl711_ai_load_counters(dev);
@@ -410,31 +404,15 @@ static int pcl711_ao_insn_write(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- struct pcl711_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int val = devpriv->ao_readback[chan];
+ unsigned int val = s->readback[chan];
int i;
for (i = 0; i < insn->n; i++) {
val = data[i];
pcl711_ao_write(dev, chan, val);
}
- devpriv->ao_readback[chan] = val;
-
- return insn->n;
-}
-
-static int pcl711_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct pcl711_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];
+ s->readback[chan] = val;
return insn->n;
}
@@ -476,7 +454,7 @@ static int pcl711_do_insn_bits(struct comedi_device *dev,
static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct pcl711_board *board = comedi_board(dev);
+ const struct pcl711_board *board = dev->board_ptr;
struct pcl711_private *devpriv;
struct comedi_subdevice *s;
int ret;
@@ -527,7 +505,11 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->maxdata = 0xfff;
s->range_table = &range_bipolar5;
s->insn_write = pcl711_ao_insn_write;
- s->insn_read = pcl711_ao_insn_read;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
/* Digital Input subdevice */
s = &dev->subdevices[2];
diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c
index c7f8eb1cf8de..fcc440855e66 100644
--- a/drivers/staging/comedi/drivers/pcl724.c
+++ b/drivers/staging/comedi/drivers/pcl724.c
@@ -32,8 +32,6 @@
#include "8255.h"
-#define SIZE_8255 4
-
struct pcl724_board {
const char *name;
unsigned int io_range;
@@ -81,10 +79,11 @@ static const struct pcl724_board boardtypes[] = {
},
};
-static int pcl724_8255mapped_io(int dir, int port, int data,
+static int pcl724_8255mapped_io(struct comedi_device *dev,
+ int dir, int port, int data,
unsigned long iobase)
{
- int movport = SIZE_8255 * (iobase >> 12);
+ int movport = I8255_SIZE * (iobase >> 12);
iobase &= 0x0fff;
@@ -99,7 +98,7 @@ static int pcl724_8255mapped_io(int dir, int port, int data,
static int pcl724_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- const struct pcl724_board *board = comedi_board(dev);
+ const struct pcl724_board *board = dev->board_ptr;
struct comedi_subdevice *s;
unsigned long iobase;
unsigned int iorange;
@@ -132,8 +131,7 @@ static int pcl724_attach(struct comedi_device *dev,
ret = subdev_8255_init(dev, s, pcl724_8255mapped_io,
iobase);
} else {
- iobase = dev->iobase + (i * SIZE_8255);
- ret = subdev_8255_init(dev, s, NULL, iobase);
+ ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE);
}
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index 74f6489bd124..dc179bd02dfd 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -156,7 +156,6 @@ static const struct pcl726_board pcl726_boards[] = {
struct pcl726_private {
const struct comedi_lrange *rangelist[12];
- unsigned int ao_readback[12];
unsigned int cmd_running:1;
};
@@ -189,9 +188,6 @@ static int pcl726_intr_cmdtest(struct comedi_device *dev,
/* Step 2a : make sure trigger sources are unique */
/* 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);
@@ -203,10 +199,9 @@ static int pcl726_intr_cmdtest(struct comedi_device *dev,
if (err)
return 3;
- /* step 4: ignored */
+ /* Step 4: fix up any arguments */
- if (err)
- return 4;
+ /* Step 5: check channel list if it exists */
return 0;
}
@@ -253,15 +248,14 @@ static int pcl726_ao_insn_write(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- struct pcl726_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;
+ unsigned int val = data[i];
+
+ s->readback[chan] = val;
/* bipolar data to the DAC is two's complement */
if (comedi_chan_range_is_bipolar(s, chan, range))
@@ -275,27 +269,12 @@ static int pcl726_ao_insn_write(struct comedi_device *dev,
return insn->n;
}
-static int pcl726_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct pcl726_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 pcl726_di_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
{
- const struct pcl726_board *board = comedi_board(dev);
+ const struct pcl726_board *board = dev->board_ptr;
unsigned int val;
if (board->is_pcl727) {
@@ -316,7 +295,7 @@ static int pcl726_do_insn_bits(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- const struct pcl726_board *board = comedi_board(dev);
+ const struct pcl726_board *board = dev->board_ptr;
unsigned long io = dev->iobase;
unsigned int mask;
@@ -343,7 +322,7 @@ static int pcl726_do_insn_bits(struct comedi_device *dev,
static int pcl726_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- const struct pcl726_board *board = comedi_board(dev);
+ const struct pcl726_board *board = dev->board_ptr;
struct pcl726_private *devpriv;
struct comedi_subdevice *s;
int subdev;
@@ -398,7 +377,11 @@ static int pcl726_attach(struct comedi_device *dev,
s->maxdata = 0x0fff;
s->range_table_list = devpriv->rangelist;
s->insn_write = pcl726_ao_insn_write;
- s->insn_read = pcl726_ao_insn_read;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
if (board->have_dio) {
/* Digital Input subdevice */
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index bdce24c42940..a6c5770b2808 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -270,7 +270,7 @@ static int pcl730_di_insn_bits(struct comedi_device *dev,
static int pcl730_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- const struct pcl730_board *board = comedi_board(dev);
+ const struct pcl730_board *board = dev->board_ptr;
struct comedi_subdevice *s;
int subdev;
int ret;
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index 803e7790538c..fd5ea6e01619 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -522,7 +522,6 @@ struct pcl812_private {
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;
@@ -714,7 +713,7 @@ static int pcl812_ai_eoc(struct comedi_device *dev,
static int pcl812_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
- const struct pcl812_board *board = comedi_board(dev);
+ const struct pcl812_board *board = dev->board_ptr;
struct pcl812_private *devpriv = dev->private;
int err = 0;
unsigned int flags;
@@ -813,7 +812,7 @@ 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 (cmd->flags & TRIG_WAKE_EOS) {
+ if (cmd->flags & CMDF_WAKE_EOS) {
devpriv->ai_eos = 1;
/* DMA is useless for this situation */
@@ -1039,32 +1038,16 @@ static int pcl812_ao_insn_write(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- struct pcl812_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = s->readback[chan];
int i;
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];
+ val = data[i];
+ outb(val & 0xff, dev->iobase + PCL812_AO_LSB_REG(chan));
+ outb((val >> 8) & 0x0f, dev->iobase + PCL812_AO_MSB_REG(chan));
}
-
- return insn->n;
-}
-
-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;
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
+ s->readback[chan] = val;
return insn->n;
}
@@ -1097,7 +1080,7 @@ static int pcl812_do_insn_bits(struct comedi_device *dev,
static void pcl812_reset(struct comedi_device *dev)
{
- const struct pcl812_board *board = comedi_board(dev);
+ const struct pcl812_board *board = dev->board_ptr;
struct pcl812_private *devpriv = dev->private;
unsigned int chan;
@@ -1134,7 +1117,7 @@ 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);
+ const struct pcl812_board *board = dev->board_ptr;
struct pcl812_private *devpriv = dev->private;
/* default to the range table from the boardinfo */
@@ -1222,7 +1205,7 @@ static void pcl812_set_ai_range_table(struct comedi_device *dev,
static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct pcl812_board *board = comedi_board(dev);
+ const struct pcl812_board *board = dev->board_ptr;
struct pcl812_private *devpriv;
struct comedi_subdevice *s;
int n_subdevices;
@@ -1336,8 +1319,6 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
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)
@@ -1353,6 +1334,13 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->range_table = &range_unknown;
break;
}
+ s->insn_write = pcl812_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
+
subdev++;
}
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index 54732c5cab97..aa6487132017 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -671,7 +671,7 @@ static void pcl816_reset(struct comedi_device *dev)
static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct pcl816_board *board = comedi_board(dev);
+ const struct pcl816_board *board = dev->board_ptr;
struct pcl816_private *devpriv;
struct comedi_subdevice *s;
int ret;
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index 000dbf841e45..ac19e83ce62a 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -319,7 +319,6 @@ struct pcl818_private {
unsigned int act_chanlist_len; /* how long is actual MUX list */
unsigned int act_chanlist_pos; /* actual position in MUX list */
unsigned int ai_data_len; /* len of data buffer */
- unsigned int ao_readback[2];
unsigned int divisor1;
unsigned int divisor2;
unsigned int usefifo:1;
@@ -739,7 +738,7 @@ static int check_single_ended(unsigned int port)
static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct pcl818_board *board = comedi_board(dev);
+ const struct pcl818_board *board = dev->board_ptr;
struct pcl818_private *devpriv = dev->private;
int err = 0;
unsigned int arg;
@@ -937,32 +936,18 @@ static int pcl818_ao_insn_write(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- struct pcl818_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val = s->readback[chan];
int i;
for (i = 0; i < insn->n; i++) {
- devpriv->ao_readback[chan] = data[i];
- outb((data[i] & 0x000f) << 4,
+ val = data[i];
+ outb((val & 0x000f) << 4,
dev->iobase + PCL818_AO_LSB_REG(chan));
- outb((data[i] & 0x0ff0) >> 4,
+ outb((val & 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];
+ s->readback[chan] = val;
return insn->n;
}
@@ -995,7 +980,7 @@ static int pcl818_do_insn_bits(struct comedi_device *dev,
static void pcl818_reset(struct comedi_device *dev)
{
- const struct pcl818_board *board = comedi_board(dev);
+ const struct pcl818_board *board = dev->board_ptr;
unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE;
unsigned int chan;
@@ -1033,7 +1018,7 @@ 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);
+ const struct pcl818_board *board = dev->board_ptr;
/* default to the range table from the boardinfo */
s->range_table = board->ai_range_type;
@@ -1082,7 +1067,7 @@ static void pcl818_set_ai_range_table(struct comedi_device *dev,
static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct pcl818_board *board = comedi_board(dev);
+ const struct pcl818_board *board = dev->board_ptr;
struct pcl818_private *devpriv;
struct comedi_subdevice *s;
int ret;
@@ -1172,8 +1157,6 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
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;
@@ -1185,6 +1168,12 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (it->options[5] == 2)
s->range_table = &range_unknown;
}
+ s->insn_write = pcl818_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c
index 6e0d78f6095b..6176dfa24801 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -33,8 +33,6 @@ Copy/pasted/hacked from pcm724.c
#include "8255.h"
-#define SIZE_8255 4
-
#define BUF_C0 0x1
#define BUF_B0 0x2
#define BUF_A0 0x4
@@ -49,16 +47,6 @@ Copy/pasted/hacked from pcm724.c
#define GATE_B1 0x10
#define GATE_C1 0x8
-/* from 8255.c */
-#define CR_CW 0x80
-#define _8255_CR 3
-#define CR_B_IO 0x02
-#define CR_B_MODE 0x04
-#define CR_C_IO 0x09
-#define CR_A_IO 0x10
-#define CR_A_MODE(a) ((a)<<5)
-#define CR_CW 0x80
-
/* used to track configured dios */
struct priv_pcm3724 {
int dio_1;
@@ -98,26 +86,26 @@ static void do_3724_config(struct comedi_device *dev,
int buffer_config;
unsigned long port_8255_cfg;
- config = CR_CW;
+ config = I8255_CTRL_CW;
buffer_config = 0;
/* 1 in io_bits indicates output, 1 in config indicates input */
if (!(s->io_bits & 0x0000ff))
- config |= CR_A_IO;
+ config |= I8255_CTRL_A_IO;
if (!(s->io_bits & 0x00ff00))
- config |= CR_B_IO;
+ config |= I8255_CTRL_B_IO;
if (!(s->io_bits & 0xff0000))
- config |= CR_C_IO;
+ config |= I8255_CTRL_C_HI_IO | I8255_CTRL_C_LO_IO;
buffer_config = compute_buffer(0, 0, s_dio1);
buffer_config = compute_buffer(buffer_config, 1, s_dio2);
if (s == s_dio1)
- port_8255_cfg = dev->iobase + _8255_CR;
+ port_8255_cfg = dev->iobase + I8255_CTRL_REG;
else
- port_8255_cfg = dev->iobase + SIZE_8255 + _8255_CR;
+ port_8255_cfg = dev->iobase + I8255_SIZE + I8255_CTRL_REG;
outb(buffer_config, dev->iobase + 8); /* update buffer register */
@@ -211,8 +199,7 @@ static int pcm3724_attach(struct comedi_device *dev,
for (i = 0; i < dev->n_subdevices; i++) {
s = &dev->subdevices[i];
- ret = subdev_8255_init(dev, s, NULL,
- dev->iobase + SIZE_8255 * i);
+ ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE);
if (ret)
return ret;
s->insn_config = subdev_3724_insn_config;
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index 87c61d9b11da..e3ac8ac6190e 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -112,7 +112,7 @@ static int pcmad_ai_insn_read(struct comedi_device *dev,
static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct pcmad_board_struct *board = comedi_board(dev);
+ const struct pcmad_board_struct *board = dev->board_ptr;
struct comedi_subdevice *s;
int ret;
diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c
index 1c7a135c91d6..59108c06cedc 100644
--- a/drivers/staging/comedi/drivers/pcmda12.c
+++ b/drivers/staging/comedi/drivers/pcmda12.c
@@ -61,7 +61,6 @@ static const struct comedi_lrange pcmda12_ranges = {
};
struct pcmda12_private {
- unsigned int ao_readback[8];
int simultaneous_xfer_mode;
};
@@ -72,7 +71,7 @@ static int pcmda12_ao_insn_write(struct comedi_device *dev,
{
struct pcmda12_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int val = devpriv->ao_readback[chan];
+ unsigned int val = s->readback[chan];
unsigned long ioreg = dev->iobase + (chan * 2);
int i;
@@ -88,7 +87,7 @@ static int pcmda12_ao_insn_write(struct comedi_device *dev,
if (!devpriv->simultaneous_xfer_mode)
inb(ioreg);
}
- devpriv->ao_readback[chan] = val;
+ s->readback[chan] = val;
return insn->n;
}
@@ -99,8 +98,6 @@ static int pcmda12_ao_insn_read(struct comedi_device *dev,
unsigned int *data)
{
struct pcmda12_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int i;
/*
* Initiate simultaneaous xfer mode by reading one of the
@@ -109,10 +106,7 @@ static int pcmda12_ao_insn_read(struct comedi_device *dev,
if (devpriv->simultaneous_xfer_mode)
inb(dev->iobase);
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return insn->n;
+ return comedi_readback_insn_read(dev, s, insn, data);
}
static void pcmda12_ao_reset(struct comedi_device *dev,
@@ -158,6 +152,10 @@ static int pcmda12_attach(struct comedi_device *dev,
s->insn_write = pcmda12_ao_insn_write;
s->insn_read = pcmda12_ao_insn_read;
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
+
pcmda12_ao_reset(dev, s);
return 0;
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index fed7e77e0305..fc40ee2b34e9 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -192,8 +192,6 @@ struct pcmmio_private {
unsigned int enabled_mask;
unsigned int stop_count;
unsigned int active:1;
-
- unsigned int ao_readback[8];
};
static void pcmmio_dio_write(struct comedi_device *dev, unsigned int val,
@@ -408,8 +406,8 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d)
}
/* devpriv->spinlock is already locked */
-static int pcmmio_start_intr(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static void pcmmio_start_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct pcmmio_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
@@ -417,13 +415,6 @@ static int pcmmio_start_intr(struct comedi_device *dev,
unsigned int pol_bits = 0;
int i;
- if (cmd->stop_src == TRIG_COUNT && devpriv->stop_count == 0) {
- /* An empty acquisition! */
- s->async->events |= COMEDI_CB_EOA;
- devpriv->active = 0;
- return 1;
- }
-
devpriv->enabled_mask = 0;
devpriv->active = 1;
if (cmd->chanlist) {
@@ -443,8 +434,6 @@ static int pcmmio_start_intr(struct comedi_device *dev,
/* set polarity and enable interrupts */
pcmmio_dio_write(dev, pol_bits, PCMMIO_PAGE_POL, 0);
pcmmio_dio_write(dev, bits, PCMMIO_PAGE_ENAB, 0);
-
- return 0;
}
static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
@@ -467,7 +456,6 @@ static int pcmmio_inttrig_start_intr(struct comedi_device *dev,
struct pcmmio_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned long flags;
- int event = 0;
if (trig_num != cmd->start_arg)
return -EINVAL;
@@ -475,12 +463,9 @@ static int pcmmio_inttrig_start_intr(struct comedi_device *dev,
spin_lock_irqsave(&devpriv->spinlock, flags);
s->async->inttrig = NULL;
if (devpriv->active)
- event = pcmmio_start_intr(dev, s);
+ pcmmio_start_intr(dev, s);
spin_unlock_irqrestore(&devpriv->spinlock, flags);
- if (event)
- comedi_event(dev, s);
-
return 1;
}
@@ -492,28 +477,20 @@ static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
struct pcmmio_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned long flags;
- int event = 0;
spin_lock_irqsave(&devpriv->spinlock, flags);
devpriv->active = 1;
- /* Set up end of acquisition. */
- if (cmd->stop_src == TRIG_COUNT)
- devpriv->stop_count = cmd->stop_arg;
- else /* TRIG_NONE */
- devpriv->stop_count = 0;
+ devpriv->stop_count = cmd->stop_arg;
/* Set up start of acquisition. */
if (cmd->start_src == TRIG_INT)
s->async->inttrig = pcmmio_inttrig_start_intr;
else /* TRIG_NOW */
- event = pcmmio_start_intr(dev, s);
+ pcmmio_start_intr(dev, s);
spin_unlock_irqrestore(&devpriv->spinlock, flags);
- if (event)
- comedi_event(dev, s);
-
return 0;
}
@@ -551,16 +528,10 @@ static int pcmmio_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);
- switch (cmd->stop_src) {
- case TRIG_COUNT:
- /* any count allowed */
- break;
- case TRIG_NONE:
+ 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);
- break;
- default:
- break;
- }
if (err)
return 3;
@@ -655,21 +626,6 @@ static int pcmmio_ai_insn_read(struct comedi_device *dev,
return insn->n;
}
-static int pcmmio_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct pcmmio_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int i;
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return insn->n;
-}
-
static int pcmmio_ao_eoc(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -688,11 +644,9 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- struct pcmmio_private *devpriv = dev->private;
unsigned long iobase = dev->iobase;
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int range = CR_RANGE(insn->chanspec);
- unsigned int val = devpriv->ao_readback[chan];
unsigned char cmd = 0;
int ret;
int i;
@@ -719,7 +673,7 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev,
return ret;
for (i = 0; i < insn->n; i++) {
- val = data[i];
+ unsigned int val = data[i];
/* write the data to the channel */
outb(val & 0xff, iobase + PCMMIO_AO_LSB_REG);
@@ -731,7 +685,7 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev,
if (ret)
return ret;
- devpriv->ao_readback[chan] = val;
+ s->readback[chan] = val;
}
return insn->n;
@@ -796,8 +750,12 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->n_chan = 8;
s->maxdata = 0xffff;
s->range_table = &pcmmio_ao_ranges;
- s->insn_read = pcmmio_ao_insn_read;
s->insn_write = pcmmio_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
/* initialize the resource enable register by clearing it */
outb(0, dev->iobase + PCMMIO_AO_RESOURCE_ENA_REG);
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index 1bca3fba0950..d4fe2ec25ecf 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -132,7 +132,6 @@ struct pcmuio_asic {
unsigned int enabled_mask;
unsigned int stop_count;
unsigned int active:1;
- unsigned int continuous:1;
};
struct pcmuio_private {
@@ -279,7 +278,7 @@ static int pcmuio_dio_insn_config(struct comedi_device *dev,
static void pcmuio_reset(struct comedi_device *dev)
{
- const struct pcmuio_board *board = comedi_board(dev);
+ const struct pcmuio_board *board = dev->board_ptr;
int asic;
for (asic = 0; asic < board->num_asics; ++asic) {
@@ -349,8 +348,7 @@ static void pcmuio_handle_intr_subdev(struct comedi_device *dev,
}
/* Check for end of acquisition. */
- if (!chip->continuous) {
- /* stop_src == TRIG_COUNT */
+ if (cmd->stop_src == TRIG_COUNT) {
if (chip->stop_count > 0) {
chip->stop_count--;
if (chip->stop_count == 0) {
@@ -405,8 +403,8 @@ static irqreturn_t pcmuio_interrupt(int irq, void *d)
}
/* chip->spinlock is already locked */
-static int pcmuio_start_intr(struct comedi_device *dev,
- struct comedi_subdevice *s)
+static void pcmuio_start_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct pcmuio_private *devpriv = dev->private;
int asic = pcmuio_subdevice_to_asic(s);
@@ -416,13 +414,6 @@ static int pcmuio_start_intr(struct comedi_device *dev,
unsigned int pol_bits = 0;
int i;
- if (!chip->continuous && chip->stop_count == 0) {
- /* An empty acquisition! */
- s->async->events |= COMEDI_CB_EOA;
- chip->active = 0;
- return 1;
- }
-
chip->enabled_mask = 0;
chip->active = 1;
if (cmd->chanlist) {
@@ -442,8 +433,6 @@ static int pcmuio_start_intr(struct comedi_device *dev,
/* set pol and enab intrs for this subdev.. */
pcmuio_write(dev, pol_bits, asic, PCMUIO_PAGE_POL, 0);
pcmuio_write(dev, bits, asic, PCMUIO_PAGE_ENAB, 0);
-
- return 0;
}
static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
@@ -470,7 +459,6 @@ static int pcmuio_inttrig_start_intr(struct comedi_device *dev,
int asic = pcmuio_subdevice_to_asic(s);
struct pcmuio_asic *chip = &devpriv->asics[asic];
unsigned long flags;
- int event = 0;
if (trig_num != cmd->start_arg)
return -EINVAL;
@@ -478,13 +466,10 @@ static int pcmuio_inttrig_start_intr(struct comedi_device *dev,
spin_lock_irqsave(&chip->spinlock, flags);
s->async->inttrig = NULL;
if (chip->active)
- event = pcmuio_start_intr(dev, s);
+ pcmuio_start_intr(dev, s);
spin_unlock_irqrestore(&chip->spinlock, flags);
- if (event)
- comedi_event(dev, s);
-
return 1;
}
@@ -498,35 +483,20 @@ static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
int asic = pcmuio_subdevice_to_asic(s);
struct pcmuio_asic *chip = &devpriv->asics[asic];
unsigned long flags;
- int event = 0;
spin_lock_irqsave(&chip->spinlock, flags);
chip->active = 1;
- /* Set up end of acquisition. */
- switch (cmd->stop_src) {
- case TRIG_COUNT:
- chip->continuous = 0;
- chip->stop_count = cmd->stop_arg;
- break;
- default:
- /* TRIG_NONE */
- chip->continuous = 1;
- chip->stop_count = 0;
- break;
- }
+ chip->stop_count = cmd->stop_arg;
/* Set up start of acquisition. */
if (cmd->start_src == TRIG_INT)
s->async->inttrig = pcmuio_inttrig_start_intr;
else /* TRIG_NOW */
- event = pcmuio_start_intr(dev, s);
+ pcmuio_start_intr(dev, s);
spin_unlock_irqrestore(&chip->spinlock, flags);
- if (event)
- comedi_event(dev, s);
-
return 0;
}
@@ -564,16 +534,10 @@ static int pcmuio_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);
- switch (cmd->stop_src) {
- case TRIG_COUNT:
- /* any count allowed */
- break;
- case TRIG_NONE:
+ 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);
- break;
- default:
- break;
- }
if (err)
return 3;
@@ -587,7 +551,7 @@ static int pcmuio_cmdtest(struct comedi_device *dev,
static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct pcmuio_board *board = comedi_board(dev);
+ const struct pcmuio_board *board = dev->board_ptr;
struct comedi_subdevice *s;
struct pcmuio_private *devpriv;
int ret;
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index b1db61d9d834..6407df0404f0 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -638,7 +638,6 @@ static int daqp_ao_insn_write(struct comedi_device *dev,
{
struct daqp_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int val;
int i;
if (devpriv->stop)
@@ -648,7 +647,10 @@ static int daqp_ao_insn_write(struct comedi_device *dev,
outb(0, dev->iobase + DAQP_AUX);
for (i = 0; i > insn->n; i++) {
- val = data[0];
+ unsigned val = data[i];
+
+ s->readback[chan] = val;
+
val &= 0x0fff;
val ^= 0x0800; /* Flip the sign */
val |= (chan << 12);
@@ -739,6 +741,11 @@ static int daqp_auto_attach(struct comedi_device *dev,
s->maxdata = 0x0fff;
s->range_table = &range_bipolar5;
s->insn_write = daqp_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[2];
s->type = COMEDI_SUBD_DI;
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 6fc4ed33f66c..7d4cb140959c 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -380,7 +380,6 @@ struct rtd_private {
int xfer_count; /* # to transfer data. 0->1/2FIFO */
int flags; /* flag event modes */
DECLARE_BITMAP(chan_is_bipolar, RTD_MAX_CHANLIST);
- unsigned int ao_readback[2];
unsigned fifosz;
};
@@ -400,15 +399,15 @@ static int rtd_ns_to_timer_base(unsigned int *nanosec,
{
int divider;
- switch (flags & TRIG_ROUND_MASK) {
- case TRIG_ROUND_NEAREST:
+ switch (flags & CMDF_ROUND_MASK) {
+ case CMDF_ROUND_NEAREST:
default:
divider = (*nanosec + base / 2) / base;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
divider = (*nanosec) / base;
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
divider = (*nanosec + base - 1) / base;
break;
}
@@ -438,7 +437,7 @@ static int rtd_ns_to_timer(unsigned int *ns, unsigned int flags)
static unsigned short rtd_convert_chan_gain(struct comedi_device *dev,
unsigned int chanspec, int index)
{
- const struct rtd_boardinfo *board = comedi_board(dev);
+ const struct rtd_boardinfo *board = dev->board_ptr;
struct rtd_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(chanspec);
unsigned int range = CR_RANGE(chanspec);
@@ -809,26 +808,26 @@ static int rtd_ai_cmdtest(struct comedi_device *dev,
if (cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
RTD_MAX_SPEED_1)) {
rtd_ns_to_timer(&cmd->scan_begin_arg,
- TRIG_ROUND_UP);
+ CMDF_ROUND_UP);
err |= -EINVAL;
}
if (cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
RTD_MIN_SPEED_1)) {
rtd_ns_to_timer(&cmd->scan_begin_arg,
- TRIG_ROUND_DOWN);
+ CMDF_ROUND_DOWN);
err |= -EINVAL;
}
} else {
if (cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
RTD_MAX_SPEED)) {
rtd_ns_to_timer(&cmd->scan_begin_arg,
- TRIG_ROUND_UP);
+ CMDF_ROUND_UP);
err |= -EINVAL;
}
if (cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
RTD_MIN_SPEED)) {
rtd_ns_to_timer(&cmd->scan_begin_arg,
- TRIG_ROUND_DOWN);
+ CMDF_ROUND_DOWN);
err |= -EINVAL;
}
}
@@ -844,26 +843,26 @@ static int rtd_ai_cmdtest(struct comedi_device *dev,
if (cfc_check_trigger_arg_min(&cmd->convert_arg,
RTD_MAX_SPEED_1)) {
rtd_ns_to_timer(&cmd->convert_arg,
- TRIG_ROUND_UP);
+ CMDF_ROUND_UP);
err |= -EINVAL;
}
if (cfc_check_trigger_arg_max(&cmd->convert_arg,
RTD_MIN_SPEED_1)) {
rtd_ns_to_timer(&cmd->convert_arg,
- TRIG_ROUND_DOWN);
+ CMDF_ROUND_DOWN);
err |= -EINVAL;
}
} else {
if (cfc_check_trigger_arg_min(&cmd->convert_arg,
RTD_MAX_SPEED)) {
rtd_ns_to_timer(&cmd->convert_arg,
- TRIG_ROUND_UP);
+ CMDF_ROUND_UP);
err |= -EINVAL;
}
if (cfc_check_trigger_arg_max(&cmd->convert_arg,
RTD_MIN_SPEED)) {
rtd_ns_to_timer(&cmd->convert_arg,
- TRIG_ROUND_DOWN);
+ CMDF_ROUND_DOWN);
err |= -EINVAL;
}
}
@@ -875,12 +874,10 @@ static int rtd_ai_cmdtest(struct comedi_device *dev,
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 {
- /* TRIG_NONE */
+ 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;
@@ -956,7 +953,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (TRIG_TIMER == cmd->scan_begin_src) {
/* scan_begin_arg is in nanoseconds */
/* find out how many samples to wait before transferring */
- if (cmd->flags & TRIG_WAKE_EOS) {
+ if (cmd->flags & CMDF_WAKE_EOS) {
/*
* this may generate un-sustainable interrupt rates
* the application is responsible for doing the
@@ -1020,7 +1017,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
switch (cmd->scan_begin_src) {
case TRIG_TIMER: /* periodic scanning */
timer = rtd_ns_to_timer(&cmd->scan_begin_arg,
- TRIG_ROUND_NEAREST);
+ CMDF_ROUND_NEAREST);
/* set PACER clock */
writel(timer & 0xffffff, dev->mmio + LAS0_PCLK);
@@ -1038,7 +1035,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (cmd->chanlist_len > 1) {
/* only needed for multi-channel */
timer = rtd_ns_to_timer(&cmd->convert_arg,
- TRIG_ROUND_NEAREST);
+ CMDF_ROUND_NEAREST);
/* setup BURST clock */
writel(timer & 0x3ff, dev->mmio + LAS0_BCLK);
}
@@ -1138,7 +1135,7 @@ static int rtd_ao_winsn(struct comedi_device *dev,
((chan == 0) ? LAS1_DAC1_FIFO : LAS1_DAC2_FIFO));
writew(0, dev->mmio + ((chan == 0) ? LAS0_DAC1 : LAS0_DAC2));
- devpriv->ao_readback[chan] = data[i];
+ s->readback[chan] = data[i];
ret = comedi_timeout(dev, s, insn, rtd_ao_eoc, 0);
if (ret)
@@ -1149,23 +1146,6 @@ static int rtd_ao_winsn(struct comedi_device *dev,
return i;
}
-/* AO subdevices should have a read insn as well as a write insn.
- * Usually this means copying a value stored in devpriv. */
-static int rtd_ao_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
-{
- struct rtd_private *devpriv = dev->private;
- int i;
- int chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
-
- return i;
-}
-
static int rtd_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -1323,7 +1303,11 @@ static int rtd_auto_attach(struct comedi_device *dev,
s->maxdata = 0x0fff;
s->range_table = &rtd_ao_range;
s->insn_write = rtd_ao_winsn;
- s->insn_read = rtd_ao_rinsn;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[2];
/* digital i/o subdevice */
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index 2b1db9783bd6..e3d9f44cefb9 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -137,7 +137,6 @@ struct rti800_private {
bool adc_2comp;
bool dac_2comp[2];
const struct comedi_lrange *ao_range_type_list[2];
- unsigned int ao_readback[2];
unsigned char muxgain_bits;
};
@@ -207,21 +206,6 @@ static int rti800_ai_insn_read(struct comedi_device *dev,
return insn->n;
}
-static int rti800_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct rti800_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 rti800_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -231,11 +215,13 @@ static int rti800_ao_insn_write(struct comedi_device *dev,
unsigned int chan = CR_CHAN(insn->chanspec);
int reg_lo = chan ? RTI800_DAC1LO : RTI800_DAC0LO;
int reg_hi = chan ? RTI800_DAC1HI : RTI800_DAC0HI;
- int val = devpriv->ao_readback[chan];
int i;
for (i = 0; i < insn->n; i++) {
- val = data[i];
+ unsigned int val = data[i];
+
+ s->readback[chan] = val;
+
if (devpriv->dac_2comp[chan])
val ^= 0x800;
@@ -243,8 +229,6 @@ static int rti800_ao_insn_write(struct comedi_device *dev,
outb((val >> 8) & 0xff, dev->iobase + reg_hi);
}
- devpriv->ao_readback[chan] = val;
-
return insn->n;
}
@@ -274,7 +258,7 @@ static int rti800_do_insn_bits(struct comedi_device *dev,
static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct rti800_board *board = comedi_board(dev);
+ const struct rti800_board *board = dev->board_ptr;
struct rti800_private *devpriv;
struct comedi_subdevice *s;
int ret;
@@ -318,8 +302,6 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE;
s->n_chan = 2;
- s->insn_read = rti800_ao_insn_read;
- s->insn_write = rti800_ao_insn_write;
s->maxdata = 0x0fff;
s->range_table_list = devpriv->ao_range_type_list;
devpriv->ao_range_type_list[0] =
@@ -330,6 +312,12 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
(it->options[7] < ARRAY_SIZE(rti800_ao_ranges))
? rti800_ao_ranges[it->options[7]]
: &range_unknown;
+ s->insn_write = rti800_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index 605a31d702e0..c81b01c40f12 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -45,24 +45,8 @@ struct rti802_private {
dac_2comp, dac_straight
} dac_coding[8];
const struct comedi_lrange *range_type_list[8];
- unsigned int ao_readback[8];
};
-static int rti802_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- 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[chan];
-
- return insn->n;
-}
-
static int rti802_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
@@ -70,15 +54,14 @@ static int rti802_ao_insn_write(struct comedi_device *dev,
{
struct rti802_private *devpriv = dev->private;
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++) {
- val = data[i];
+ unsigned int val = data[i];
- devpriv->ao_readback[chan] = val;
+ s->readback[chan] = val;
/* munge offset binary to two's complement if needed */
if (devpriv->dac_coding[chan] == dac_2comp)
@@ -116,10 +99,14 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
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;
+ s->insn_read = comedi_readback_insn_read;
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
+
+ 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);
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index 83f7433c2452..75872c6aec2a 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -111,7 +111,6 @@ union cmReg {
};
struct s526_private {
- unsigned int ao_readback[2];
unsigned int gpct_config[4];
unsigned short ai_config;
};
@@ -467,38 +466,26 @@ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
return n;
}
-static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int s526_ao_insn_write(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);
- unsigned short val;
+ unsigned int val = s->readback[chan];
int i;
- val = chan << 1;
- outw(val, dev->iobase + REG_DAC);
+ outw(chan << 1, dev->iobase + REG_DAC);
for (i = 0; i < insn->n; i++) {
- outw(data[i], dev->iobase + REG_ADD);
- devpriv->ao_readback[chan] = data[i];
+ val = data[i];
+ outw(val, dev->iobase + REG_ADD);
/* starts the D/A conversion */
- outw(val + 1, dev->iobase + REG_DAC);
+ outw((chan << 1) | 1, dev->iobase + REG_DAC);
}
+ s->readback[chan] = val;
- return i;
-}
-
-static int s526_ao_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 i;
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return i;
+ return insn->n;
}
static int s526_dio_insn_bits(struct comedi_device *dev,
@@ -595,8 +582,12 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->n_chan = 4;
s->maxdata = 0xffff;
s->range_table = &range_bipolar10;
- s->insn_write = s526_ao_winsn;
- s->insn_read = s526_ao_rinsn;
+ s->insn_write = s526_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[3];
/* digital i/o subdevice */
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index 080608a840ac..0e7621e890c3 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -78,7 +78,6 @@ struct s626_buffer_dma {
struct s626_private {
uint8_t ai_cmd_running; /* ai_cmd is running */
- uint8_t ai_continuous; /* continuous acquisition */
int ai_sample_count; /* number of samples to acquire */
unsigned int ai_sample_timer; /* time between samples in
* units of the timer */
@@ -98,7 +97,6 @@ struct s626_private {
uint8_t trim_setpoint[12]; /* images of TrimDAC setpoints */
uint32_t i2c_adrs; /* I2C device address for onboard EEPROM
* (board rev dependent) */
- unsigned int ao_readback[S626_DAC_CHANNELS];
};
/* Counter overflow/index event flag masks for RDMISC2. */
@@ -1399,7 +1397,6 @@ static void s626_check_dio_interrupts(struct comedi_device *dev)
uint8_t group;
for (group = 0; group < S626_DIO_BANKS; group++) {
- irqbit = 0;
/* read interrupt type */
irqbit = s626_debi_read(dev, S626_LP_RDCAPFLG(group));
@@ -1504,19 +1501,20 @@ static bool s626_handle_eos_interrupt(struct comedi_device *dev)
/* end of scan occurs */
async->events |= COMEDI_CB_EOS;
- if (!devpriv->ai_continuous)
+ if (cmd->stop_src == TRIG_COUNT) {
devpriv->ai_sample_count--;
- if (devpriv->ai_sample_count <= 0) {
- devpriv->ai_cmd_running = 0;
+ if (devpriv->ai_sample_count <= 0) {
+ devpriv->ai_cmd_running = 0;
- /* Stop RPS program */
- s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1);
+ /* Stop RPS program */
+ s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1);
- /* send end of acquisition */
- async->events |= COMEDI_CB_EOA;
+ /* send end of acquisition */
+ async->events |= COMEDI_CB_EOA;
- /* disable master interrupt */
- finished = true;
+ /* disable master interrupt */
+ finished = true;
+ }
}
if (devpriv->ai_cmd_running && cmd->scan_begin_src == TRIG_EXT)
@@ -1969,15 +1967,15 @@ static int s626_ns_to_timer(unsigned int *nanosec, unsigned int flags)
base = 500; /* 2MHz internal clock */
- switch (flags & TRIG_ROUND_MASK) {
- case TRIG_ROUND_NEAREST:
+ switch (flags & CMDF_ROUND_MASK) {
+ case CMDF_ROUND_NEAREST:
default:
divider = (*nanosec + base / 2) / base;
break;
- case TRIG_ROUND_DOWN:
+ case CMDF_ROUND_DOWN:
divider = (*nanosec) / base;
break;
- case TRIG_ROUND_UP:
+ case CMDF_ROUND_UP:
divider = (*nanosec + base - 1) / base;
break;
}
@@ -2104,18 +2102,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
break;
}
- switch (cmd->stop_src) {
- case TRIG_COUNT:
- /* data arrives as one packet */
- devpriv->ai_sample_count = cmd->stop_arg;
- devpriv->ai_continuous = 0;
- break;
- case TRIG_NONE:
- /* continuous acquisition */
- devpriv->ai_continuous = 1;
- devpriv->ai_sample_count = 1;
- break;
- }
+ devpriv->ai_sample_count = cmd->stop_arg;
s626_reset_adc(dev, ppl);
@@ -2221,7 +2208,7 @@ static int s626_ai_cmdtest(struct comedi_device *dev,
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);
+ err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
else /* TRIG_NONE */
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
@@ -2269,38 +2256,28 @@ static int s626_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
-static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int s626_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct s626_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
int i;
- int ret;
- uint16_t chan = CR_CHAN(insn->chanspec);
- int16_t dacdata;
for (i = 0; i < insn->n; i++) {
- dacdata = (int16_t) data[i];
- devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[i];
+ int16_t dacdata = (int16_t)data[i];
+ int ret;
+
dacdata -= (0x1fff);
ret = s626_set_dac(dev, chan, dacdata);
if (ret)
return ret;
- }
-
- return i;
-}
-static int s626_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct s626_private *devpriv = dev->private;
- int i;
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
+ s->readback[chan] = data[i];
+ }
- return i;
+ return insn->n;
}
/* *************** DIGITAL I/O FUNCTIONS *************** */
@@ -2457,26 +2434,6 @@ static void s626_write_misc2(struct comedi_device *dev, uint16_t new_image)
s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_WDISABLE);
}
-static void s626_close_dma_b(struct comedi_device *dev,
- struct s626_buffer_dma *pdma, size_t bsize)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- void *vbptr;
- dma_addr_t vpptr;
-
- if (pdma == NULL)
- return;
-
- /* find the matching allocation from the board struct */
- vbptr = pdma->logical_base;
- vpptr = pdma->physical_base;
- if (vbptr) {
- pci_free_consistent(pcidev, bsize, vbptr, vpptr);
- pdma->logical_base = NULL;
- pdma->physical_base = 0;
- }
-}
-
static void s626_counters_init(struct comedi_device *dev)
{
int chan;
@@ -2527,6 +2484,24 @@ static int s626_allocate_dma_buffers(struct comedi_device *dev)
return 0;
}
+static void s626_free_dma_buffers(struct comedi_device *dev)
+{
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct s626_private *devpriv = dev->private;
+
+ if (!devpriv)
+ return;
+
+ if (devpriv->rps_buf.logical_base)
+ pci_free_consistent(pcidev, S626_DMABUF_SIZE,
+ devpriv->rps_buf.logical_base,
+ devpriv->rps_buf.physical_base);
+ if (devpriv->ana_buf.logical_base)
+ pci_free_consistent(pcidev, S626_DMABUF_SIZE,
+ devpriv->ana_buf.logical_base,
+ devpriv->ana_buf.physical_base);
+}
+
static int s626_initialize(struct comedi_device *dev)
{
struct s626_private *devpriv = dev->private;
@@ -2844,8 +2819,12 @@ static int s626_auto_attach(struct comedi_device *dev,
s->n_chan = S626_DAC_CHANNELS;
s->maxdata = 0x3fff;
s->range_table = &range_bipolar10;
- s->insn_write = s626_ao_winsn;
- s->insn_read = s626_ao_rinsn;
+ s->insn_write = s626_ao_insn_write;
+ s->insn_read = comedi_readback_insn_read;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
s = &dev->subdevices[2];
/* digital I/O subdevice */
@@ -2923,19 +2902,10 @@ static void s626_detach(struct comedi_device *dev)
/* Close all interfaces on 7146 device */
writel(S626_MC1_SHUTDOWN, dev->mmio + S626_P_MC1);
writel(S626_ACON1_BASE, dev->mmio + S626_P_ACON1);
-
- s626_close_dma_b(dev, &devpriv->rps_buf,
- S626_DMABUF_SIZE);
- s626_close_dma_b(dev, &devpriv->ana_buf,
- S626_DMABUF_SIZE);
}
-
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->mmio)
- iounmap(dev->mmio);
}
- comedi_pci_disable(dev);
+ comedi_pci_detach(dev);
+ s626_free_dma_buffers(dev);
}
static struct comedi_driver s626_driver = {
diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c
deleted file mode 100644
index a118678c24a1..000000000000
--- a/drivers/staging/comedi/drivers/skel.c
+++ /dev/null
@@ -1,726 +0,0 @@
-/*
- comedi/drivers/skel.c
- Skeleton code for a Comedi driver
-
- 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: skel
-Description: Skeleton driver, an example for driver writers
-Devices:
-Author: ds
-Updated: Mon, 18 Mar 2002 15:34:01 -0800
-Status: works
-
-This driver is a documented example on how Comedi drivers are
-written.
-
-Configuration Options:
- none
-*/
-
-/*
- * The previous block comment is used to automatically generate
- * documentation in Comedi and Comedilib. The fields:
- *
- * Driver: the name of the driver
- * Description: a short phrase describing the driver. Don't list boards.
- * Devices: a full list of the boards that attempt to be supported by
- * the driver. Format is "(manufacturer) board name [comedi name]",
- * where comedi_name is the name that is used to configure the board.
- * See the comment near board_name: in the struct comedi_driver structure
- * below. If (manufacturer) or [comedi name] is missing, the previous
- * value is used.
- * Author: you
- * Updated: date when the _documentation_ was last updated. Use 'date -R'
- * to get a value for this.
- * Status: a one-word description of the status. Valid values are:
- * works - driver works correctly on most boards supported, and
- * passes comedi_test.
- * unknown - unknown. Usually put there by ds.
- * experimental - may not work in any particular release. Author
- * probably wants assistance testing it.
- * bitrotten - driver has not been update in a long time, probably
- * doesn't work, and probably is missing support for significant
- * Comedi interface features.
- * untested - author probably wrote it "blind", and is believed to
- * work, but no confirmation.
- *
- * These headers should be followed by a blank line, and any comments
- * you wish to say about the driver. The comment area is the place
- * to put any known bugs, limitations, unsupported features, supported
- * command triggers, whether or not commands are supported on particular
- * subdevices, etc.
- *
- * Somewhere in the comment should be information about configuration
- * options that are used with comedi_config.
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-
-#include "../comedidev.h"
-
-#include "comedi_fc.h"
-
-/* Imaginary registers for the imaginary board */
-#define SKEL_START_AI_CONV 0
-#define SKEL_AI_READ 0
-
-/*
- * Board descriptions for two imaginary boards. Describing the
- * boards in this way is optional, and completely driver-dependent.
- * Some drivers use arrays such as this, other do not.
- */
-enum skel_boardid {
- BOARD_SKEL100,
- BOARD_SKEL200,
-};
-
-struct skel_board {
- const char *name;
- int ai_chans;
- int ai_bits;
- int have_dio;
-};
-
-static const struct skel_board skel_boards[] = {
- [BOARD_SKEL100] = {
- .name = "skel-100",
- .ai_chans = 16,
- .ai_bits = 12,
- .have_dio = 1,
- },
- [BOARD_SKEL200] = {
- .name = "skel-200",
- .ai_chans = 8,
- .ai_bits = 16,
- },
-};
-
-/* this structure is for data unique to this hardware driver. If
- several hardware drivers keep similar information in this structure,
- feel free to suggest moving the variable to the struct comedi_device struct.
- */
-struct skel_private {
-
- int data;
-
- /* Used for AO readback */
- unsigned int ao_readback[2];
-};
-
-/* This function doesn't require a particular form, this is just
- * what happens to be used in some of the drivers. It should
- * convert ns nanoseconds to a counter value suitable for programming
- * the device. Also, it should adjust ns so that it cooresponds to
- * the actual time that the device will use. */
-static int skel_ns_to_timer(unsigned int *ns, unsigned int flags)
-{
- /* trivial timer */
- /* if your timing is done through two cascaded timers, the
- * i8253_cascade_ns_to_timer() function in 8253.h can be
- * very helpful. There are also i8254_load() and i8254_mm_load()
- * which can be used to load values into the ubiquitous 8254 counters
- */
-
- return *ns;
-}
-
-/*
- * 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.
- */
-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;
- unsigned int d;
- int ret;
-
- /* a typical programming sequence */
-
- /* write channel to multiplexer */
- /* outw(chan,dev->iobase + SKEL_MUX); */
-
- /* don't wait for mux to settle */
-
- /* convert n samples */
- for (n = 0; n < insn->n; n++) {
- /* trigger conversion */
- /* outw(0,dev->iobase + SKEL_CONVERT); */
-
- /* wait for conversion to end */
- ret = comedi_timeout(dev, s, insn, skel_ai_eoc, 0);
- if (ret)
- return ret;
-
- /* read data */
- /* d = inw(dev->iobase + SKEL_AI_DATA); */
- d = 0;
-
- /* mangle the data as necessary */
- d ^= 1 << (thisboard->ai_bits - 1);
-
- data[n] = d;
- }
-
- /* return the number of samples read/written */
- return n;
-}
-
-/*
- * cmdtest tests a particular command to see if it is valid.
- * Using the cmdtest ioctl, a user can create a valid cmd
- * and then have it executes by the cmd ioctl.
- *
- * cmdtest returns 1,2,3,4 or 0, depending on which tests
- * the command passes.
- */
-static int skel_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
-{
- int err = 0;
- unsigned int arg;
-
- /* 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->scan_begin_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) {
- arg = cmd->scan_begin_arg;
- skel_ns_to_timer(&arg, cmd->flags);
- err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
- }
- if (cmd->convert_src == TRIG_TIMER) {
- arg = cmd->convert_arg;
- skel_ns_to_timer(&arg, cmd->flags);
- 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;
-
- return 0;
-}
-
-static int skel_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct skel_private *devpriv = dev->private;
- int i;
- int chan = CR_CHAN(insn->chanspec);
-
- /* Writing a list of values to an AO channel is probably not
- * very useful, but that's how the interface is defined. */
- for (i = 0; i < insn->n; i++) {
- /* a typical programming sequence */
- /* outw(data[i],dev->iobase + SKEL_DA0 + chan); */
- devpriv->ao_readback[chan] = data[i];
- }
-
- /* return the number of samples read/written */
- return i;
-}
-
-/* AO subdevices should have a read insn as well as a write insn.
- * Usually this means copying a value stored in devpriv. */
-static int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct skel_private *devpriv = dev->private;
- int i;
- int chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return i;
-}
-
-/*
- * DIO devices are slightly special. Although it is possible to
- * implement the insn_read/insn_write interface, it is much more
- * useful to applications if you implement the insn_bits interface.
- * This allows packed reading/writing of the DIO channels. The
- * comedi core can convert between insn_bits and insn_read/write.
- */
-static int skel_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- /*
- * The insn data is a mask in data[0] and the new data
- * in data[1], each channel cooresponding to a bit.
- *
- * The core provided comedi_dio_update_state() function can
- * be used to handle the internal state update to DIO subdevices
- * with <= 32 channels. This function will return '0' if the
- * state does not change or the mask of the channels that need
- * to be updated.
- */
- if (comedi_dio_update_state(s, data)) {
- /* Write out the new digital output lines */
- /* outw(s->state, dev->iobase + SKEL_DIO); */
- }
-
- /*
- * On return, data[1] contains the value of the digital
- * input and output lines.
- */
- /* data[1] = inw(dev->iobase + SKEL_DIO); */
-
- /*
- * Or we could just return the software copy of the output
- * values if it was a purely digital output subdevice.
- */
- /* data[1] = s->state; */
-
- return insn->n;
-}
-
-static int skel_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- int ret;
-
- /*
- * The input or output configuration of each digital line is
- * configured by special insn_config instructions.
- *
- * chanspec contains the channel to be changed
- * data[0] contains the instruction to perform on the channel
- *
- * Normally the core provided comedi_dio_insn_config() function
- * can be used to handle the boilerplpate.
- */
- ret = comedi_dio_insn_config(dev, s, insn, data, 0);
- if (ret)
- return ret;
-
- /* Update the hardware to the new configuration */
- /* outw(s->io_bits, dev->iobase + SKEL_DIO_CONFIG); */
-
- return insn->n;
-}
-
-/*
- * Handle common part of skel_attach() and skel_auto_attach().
- */
-static int skel_common_attach(struct comedi_device *dev)
-{
- const struct skel_board *thisboard = comedi_board(dev);
- struct comedi_subdevice *s;
- int ret;
-
- ret = comedi_alloc_subdevices(dev, 3);
- if (ret)
- return ret;
-
- s = &dev->subdevices[0];
- /* dev->read_subdev=s; */
- /* analog input subdevice */
- s->type = COMEDI_SUBD_AI;
- /* we support single-ended (ground) and differential */
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
- s->n_chan = thisboard->ai_chans;
- s->maxdata = (1 << thisboard->ai_bits) - 1;
- s->range_table = &range_bipolar10;
- s->len_chanlist = 16; /* This is the maximum chanlist length that
- the board can handle */
- s->insn_read = skel_ai_rinsn;
-/*
-* s->subdev_flags |= SDF_CMD_READ;
-* s->do_cmd = skel_ai_cmd;
-*/
- s->do_cmdtest = skel_ai_cmdtest;
-
- s = &dev->subdevices[1];
- /* analog output subdevice */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = 1;
- s->maxdata = 0xffff;
- s->range_table = &range_bipolar5;
- s->insn_write = skel_ao_winsn;
- s->insn_read = skel_ao_rinsn;
-
- s = &dev->subdevices[2];
- /* digital i/o subdevice */
- if (thisboard->have_dio) {
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 16;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = skel_dio_insn_bits;
- s->insn_config = skel_dio_insn_config;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- return 0;
-}
-
-/*
- * _attach is called by the Comedi core to configure the driver
- * for a particular board in response to the COMEDI_DEVCONFIG ioctl for
- * a matching board or driver name. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that address.
- *
- * Drivers that handle only PCI or USB devices do not usually support
- * manual attachment of those devices via the COMEDI_DEVCONFIG ioctl, so
- * those drivers do not have an _attach function; they just have an
- * _auto_attach function instead. (See skel_auto_attach() for an example
- * of such a function.)
- */
-static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- const struct skel_board *thisboard;
- struct skel_private *devpriv;
-
-/*
- * If you can probe the device to determine what device in a series
- * it is, this is the place to do it. Otherwise, dev->board_ptr
- * should already be initialized.
- */
- /* dev->board_ptr = skel_probe(dev, it); */
-
- thisboard = comedi_board(dev);
-
- /*
- * The dev->board_name is initialized by the comedi core before
- * calling the (*attach) function. It can be optionally set by
- * the driver if additional probing has been done.
- */
- /* dev->board_name = thisboard->name; */
-
- /* Allocate the private data */
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
-/*
- * Supported boards are usually either auto-attached via the
- * Comedi driver's _auto_attach routine, or manually attached via the
- * Comedi driver's _attach routine. In most cases, attempts to
- * manual attach boards that are usually auto-attached should be
- * rejected by this function.
- */
-/*
- * if (thisboard->bustype == pci_bustype) {
- * dev_err(dev->class_dev,
- * "Manual attachment of PCI board '%s' not supported\n",
- * thisboard->name);
- * }
- */
-
-/*
- * For ISA boards, get the i/o base address from it->options[],
- * request the i/o region and set dev->iobase * from it->options[].
- * If using interrupts, get the IRQ number from it->options[].
- */
-
- /*
- * Call a common function to handle the remaining things to do for
- * attaching ISA or PCI boards. (Extra parameters could be added
- * to pass additional information such as IRQ number.)
- */
- return skel_common_attach(dev);
-}
-
-/*
- * _auto_attach is called via comedi_pci_auto_config() (or
- * comedi_usb_auto_config(), etc.) to handle devices that can be attached
- * to the Comedi core automatically without the COMEDI_DEVCONFIG ioctl.
- *
- * The context parameter is driver dependent.
- */
-static int skel_auto_attach(struct comedi_device *dev,
- unsigned long context)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct skel_board *thisboard = NULL;
- struct skel_private *devpriv;
- int ret;
-
- /* Hack to allow unused code to be optimized out. */
- if (!IS_ENABLED(CONFIG_COMEDI_PCI_DRIVERS))
- return -EINVAL;
-
- /*
- * In this example, the _auto_attach is for a PCI device.
- *
- * The 'context' passed to this function is the id->driver_data
- * associated with the PCI device found in the id_table during
- * the modprobe. This 'context' is the index of the entry in
- * skel_boards[i] that contains the boardinfo for the PCI device.
- */
- if (context < ARRAY_SIZE(skel_boards))
- thisboard = &skel_boards[context];
- if (!thisboard)
- return -ENODEV;
-
- /*
- * Point the struct comedi_device to the matching board info
- * and set the board name.
- */
- dev->board_ptr = thisboard;
- dev->board_name = thisboard->name;
-
- /* Allocate the private data */
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
- /* Enable the PCI device. */
- ret = comedi_pci_enable(dev);
- if (ret)
- return ret;
-
- /*
- * Record the fact that the PCI device is enabled so that it can
- * be disabled during _detach().
- *
- * For this example driver, we assume PCI BAR 0 is the main I/O
- * region for the board registers and use dev->iobase to hold the
- * I/O base address and to indicate that the PCI device has been
- * enabled.
- *
- * (For boards with memory-mapped registers, dev->iobase is not
- * usually needed for register access, so can just be set to 1
- * to indicate that the PCI device has been enabled.)
- */
- dev->iobase = pci_resource_start(pcidev, 0);
-
- /*
- * Call a common function to handle the remaining things to do for
- * attaching ISA or PCI boards. (Extra parameters could be added
- * to pass additional information such as IRQ number.)
- */
- return skel_common_attach(dev);
-}
-
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static void skel_detach(struct comedi_device *dev)
-{
- const struct skel_board *thisboard = comedi_board(dev);
- struct skel_private *devpriv = dev->private;
-
- if (!thisboard || !devpriv)
- return;
-
-/*
- * Do common stuff such as freeing IRQ, unmapping remapped memory
- * regions, etc., being careful to check that the stuff is valid given
- * that _detach() is called even when _attach() or _auto_attach() return
- * an error.
- */
-
- if (IS_ENABLED(CONFIG_COMEDI_PCI_DRIVERS) /* &&
- thisboard->bustype == pci_bustype */) {
- /*
- * PCI board
- *
- * If PCI device enabled by _auto_attach() (or _attach()),
- * disable it here.
- */
- comedi_pci_disable(dev);
- } else {
- /*
- * ISA board
- *
- * Release the first I/O region requested during the
- * _attach(). This is safe to call even if the request
- * failed. If any additional I/O regions are requested
- * they need to be released by the driver.
- */
- comedi_legacy_detach(dev);
- }
-}
-
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static struct comedi_driver skel_driver = {
- .driver_name = "dummy",
- .module = THIS_MODULE,
- .attach = skel_attach,
- .auto_attach = skel_auto_attach,
- .detach = skel_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
- /* Most drivers will support multiple types of boards by
- * having an array of board structures. These were defined
- * in skel_boards[] above. Note that the element 'name'
- * was first in the structure -- Comedi uses this fact to
- * extract the name of the board without knowing any details
- * about the structure except for its length.
- * When a device is attached (by comedi_config), the name
- * of the device is given to Comedi, and Comedi tries to
- * match it by going through the list of board names. If
- * there is a match, the address of the pointer is put
- * into dev->board_ptr and driver->attach() is called.
- *
- * Note that these are not necessary if you can determine
- * the type of board in software. ISA PnP, PCI, and PCMCIA
- * devices are such boards.
- */
- .board_name = &skel_boards[0].name,
- .offset = sizeof(struct skel_board),
- .num_names = ARRAY_SIZE(skel_boards),
-};
-
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
-
-static int skel_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- return comedi_pci_auto_config(dev, &skel_driver, id->driver_data);
-}
-
-/*
- * Please add your PCI vendor ID to comedidev.h, and it will
- * be forwarded upstream.
- */
-#define PCI_VENDOR_ID_SKEL 0xdafe
-
-/*
- * This is used by modprobe to translate PCI IDs to drivers.
- * Should only be used for PCI and ISA-PnP devices
- */
-static const struct pci_device_id skel_pci_table[] = {
- { PCI_VDEVICE(SKEL, 0x0100), BOARD_SKEL100 },
- { PCI_VDEVICE(SKEL, 0x0200), BOARD_SKEL200 },
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, skel_pci_table);
-
-static struct pci_driver skel_pci_driver = {
- .name = "dummy",
- .id_table = skel_pci_table,
- .probe = skel_pci_probe,
- .remove = comedi_pci_auto_unconfig,
-};
-module_comedi_pci_driver(skel_driver, skel_pci_driver);
-#else
-module_comedi_driver(skel_driver);
-#endif
-
-MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 053bc5090530..5adbfedf780f 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -109,8 +109,6 @@ sampling rate. If you sample two channels you get 4kHz and so on.
#define USBDUX_CMD_PWM_ON 7
#define USBDUX_CMD_PWM_OFF 8
-#define USBDUX_NUM_AO_CHAN 4
-
/* timeout for the USB-transfer in ms */
#define BULK_TIMEOUT 1000
@@ -198,11 +196,9 @@ struct usbdux_private {
/* size of the PWM buffer which holds the bit pattern */
int pwm_buf_sz;
/* input buffer for the ISO-transfer */
- uint16_t *in_buf;
+ __le16 *in_buf;
/* input buffer for single insn */
- uint16_t *insn_buf;
-
- unsigned int ao_readback[USBDUX_NUM_AO_CHAN];
+ __le16 *insn_buf;
unsigned int high_speed:1;
unsigned int ai_cmd_running:1;
@@ -490,7 +486,7 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb)
*datap++ = val & 0xff;
*datap++ = (val >> 8) & 0xff;
*datap++ = chan << 6;
- devpriv->ao_readback[chan] = val;
+ s->readback[chan] = val;
s->async->events |= COMEDI_CB_BLOCK;
comedi_event(dev, s);
@@ -513,7 +509,7 @@ static void usbduxsub_ao_isoc_irq(struct urb *urb)
dev_err(dev->class_dev,
"ao urb resubm failed in int-cont. ret=%d",
ret);
- if (ret == EL2NSYNC)
+ if (ret == -EL2NSYNC)
dev_err(dev->class_dev,
"buggy USB host controller or bug in IRQ handling!\n");
@@ -627,12 +623,10 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_COUNT) {
- /* any count is allowed */
- } else {
- /* TRIG_NONE */
+ 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;
@@ -855,15 +849,13 @@ static int usbdux_ao_insn_read(struct comedi_device *dev,
unsigned int *data)
{
struct usbdux_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int i;
+ int ret;
down(&devpriv->sem);
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
+ ret = comedi_readback_insn_read(dev, s, insn, data);
up(&devpriv->sem);
- return insn->n;
+ return ret;
}
static int usbdux_ao_insn_write(struct comedi_device *dev,
@@ -873,8 +865,8 @@ static int usbdux_ao_insn_write(struct comedi_device *dev,
{
struct usbdux_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
- unsigned int val = devpriv->ao_readback[chan];
- uint16_t *p = (uint16_t *)&devpriv->dux_commands[2];
+ unsigned int val = s->readback[chan];
+ __le16 *p = (__le16 *)&devpriv->dux_commands[2];
int ret = -EBUSY;
int i;
@@ -897,8 +889,9 @@ static int usbdux_ao_insn_write(struct comedi_device *dev,
ret = send_dux_commands(dev, USBDUX_CMD_AO);
if (ret < 0)
goto ao_write_exit;
+
+ s->readback[chan] = val;
}
- devpriv->ao_readback[chan] = val;
ao_write_exit:
up(&devpriv->sem);
@@ -1008,12 +1001,10 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_COUNT) {
- /* any count is allowed */
- } else {
- /* TRIG_NONE */
+ 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;
@@ -1185,7 +1176,7 @@ static int usbdux_counter_write(struct comedi_device *dev,
{
struct usbdux_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
- uint16_t *p = (uint16_t *)&devpriv->dux_commands[2];
+ __le16 *p = (__le16 *)&devpriv->dux_commands[2];
int ret = 0;
int i;
@@ -1294,7 +1285,7 @@ static void usbduxsub_pwm_irq(struct urb *urb)
dev_err(dev->class_dev,
"pwm urb resubm failed in int-cont. ret=%d",
ret);
- if (ret == EL2NSYNC)
+ if (ret == -EL2NSYNC)
dev_err(dev->class_dev,
"buggy USB host controller or bug in IRQ handling!\n");
@@ -1720,7 +1711,7 @@ static int usbdux_auto_attach(struct comedi_device *dev,
dev->write_subdev = s;
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
- s->n_chan = USBDUX_NUM_AO_CHAN;
+ s->n_chan = 4;
s->maxdata = 0x0fff;
s->len_chanlist = s->n_chan;
s->range_table = &range_usbdux_ao_range;
@@ -1730,6 +1721,10 @@ static int usbdux_auto_attach(struct comedi_device *dev,
s->insn_read = usbdux_ao_insn_read;
s->insn_write = usbdux_ao_insn_write;
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
+
/* Digital I/O subdevice */
s = &dev->subdevices[2];
s->type = COMEDI_SUBD_DIO;
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index 94a09c16de8b..ebd68e365bac 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -75,8 +75,6 @@
/* Number of channels (16 AD and offset)*/
#define NUMCHANNELS 16
-#define USBDUXSIGMA_NUM_AO_CHAN 4
-
/* Size of one A/D value */
#define SIZEADIN ((sizeof(uint32_t)))
@@ -157,12 +155,10 @@ struct usbduxsigma_private {
/* size of the PWM buffer which holds the bit pattern */
int pwm_buf_sz;
/* input buffer for the ISO-transfer */
- uint32_t *in_buf;
+ __be32 *in_buf;
/* input buffer for single insn */
uint8_t *insn_buf;
- unsigned int ao_readback[USBDUXSIGMA_NUM_AO_CHAN];
-
unsigned high_speed:1;
unsigned ai_cmd_running:1;
unsigned ao_cmd_running:1;
@@ -428,7 +424,7 @@ static void usbduxsigma_ao_urb_complete(struct urb *urb)
}
*datap++ = val;
*datap++ = chan;
- devpriv->ao_readback[chan] = val;
+ s->readback[chan] = val;
s->async->events |= COMEDI_CB_BLOCK;
comedi_event(dev, s);
@@ -451,7 +447,7 @@ static void usbduxsigma_ao_urb_complete(struct urb *urb)
dev_err(dev->class_dev,
"%s: urb resubmit failed (%d)\n",
__func__, ret);
- if (ret == EL2NSYNC)
+ if (ret == -EL2NSYNC)
dev_err(dev->class_dev,
"buggy USB host controller or bug in IRQ handler\n");
usbduxsigma_ao_stop(dev, 0); /* w/o unlink */
@@ -562,12 +558,10 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_COUNT) {
- /* any count is allowed */
- } else {
- /* TRIG_NONE */
+ 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;
@@ -788,7 +782,7 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev,
}
/* 32 bits big endian from the A/D converter */
- val = be32_to_cpu(get_unaligned((uint32_t
+ val = be32_to_cpu(get_unaligned((__be32
*)(devpriv->insn_buf + 1)));
val &= 0x00ffffff; /* strip status byte */
val ^= 0x00800000; /* convert to unsigned */
@@ -806,15 +800,13 @@ static int usbduxsigma_ao_insn_read(struct comedi_device *dev,
unsigned int *data)
{
struct usbduxsigma_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int i;
+ int ret;
down(&devpriv->sem);
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
+ ret = comedi_readback_insn_read(dev, s, insn, data);
up(&devpriv->sem);
- return insn->n;
+ return ret;
}
static int usbduxsigma_ao_insn_write(struct comedi_device *dev,
@@ -842,7 +834,7 @@ static int usbduxsigma_ao_insn_write(struct comedi_device *dev,
up(&devpriv->sem);
return ret;
}
- devpriv->ao_readback[chan] = data[i];
+ s->readback[chan] = data[i];
}
up(&devpriv->sem);
@@ -941,12 +933,10 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
- if (cmd->stop_src == TRIG_COUNT) {
- /* any count is allowed */
- } else {
- /* TRIG_NONE */
+ 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;
@@ -1148,7 +1138,7 @@ static void usbduxsigma_pwm_urb_complete(struct urb *urb)
if (ret < 0) {
dev_err(dev->class_dev, "%s: urb resubmit failed (%d)\n",
__func__, ret);
- if (ret == EL2NSYNC)
+ if (ret == -EL2NSYNC)
dev_err(dev->class_dev,
"buggy USB host controller or bug in IRQ handler\n");
usbduxsigma_pwm_stop(dev, 0); /* w/o unlink */
@@ -1349,7 +1339,7 @@ static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan)
return ret;
/* 32 bits big endian from the A/D converter */
- val = be32_to_cpu(get_unaligned((uint32_t *)(devpriv->insn_buf + 1)));
+ val = be32_to_cpu(get_unaligned((__be32 *)(devpriv->insn_buf + 1)));
val &= 0x00ffffff; /* strip status byte */
val ^= 0x00800000; /* convert to unsigned */
@@ -1437,10 +1427,8 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev)
devpriv->dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL);
devpriv->in_buf = kzalloc(SIZEINBUF, GFP_KERNEL);
devpriv->insn_buf = kzalloc(SIZEINSNBUF, GFP_KERNEL);
- devpriv->ai_urbs = kcalloc(devpriv->n_ai_urbs, sizeof(*urb),
- GFP_KERNEL);
- devpriv->ao_urbs = kcalloc(devpriv->n_ao_urbs, sizeof(*urb),
- GFP_KERNEL);
+ devpriv->ai_urbs = kcalloc(devpriv->n_ai_urbs, sizeof(urb), GFP_KERNEL);
+ devpriv->ao_urbs = kcalloc(devpriv->n_ao_urbs, sizeof(urb), GFP_KERNEL);
if (!devpriv->dux_commands || !devpriv->in_buf || !devpriv->insn_buf ||
!devpriv->ai_urbs || !devpriv->ao_urbs)
return -ENOMEM;
@@ -1613,7 +1601,7 @@ static int usbduxsigma_auto_attach(struct comedi_device *dev,
dev->write_subdev = s;
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
- s->n_chan = USBDUXSIGMA_NUM_AO_CHAN;
+ s->n_chan = 4;
s->len_chanlist = s->n_chan;
s->maxdata = 0x00ff;
s->range_table = &range_unipolar2_5;
@@ -1623,6 +1611,10 @@ static int usbduxsigma_auto_attach(struct comedi_device *dev,
s->do_cmd = usbduxsigma_ao_cmd;
s->cancel = usbduxsigma_ao_cancel;
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
+
/* Digital I/O subdevice */
s = &dev->subdevices[2];
s->type = COMEDI_SUBD_DIO;
diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c
index 831c3b702899..71003416edcf 100644
--- a/drivers/staging/comedi/drivers/vmk80xx.c
+++ b/drivers/staging/comedi/drivers/vmk80xx.c
@@ -767,7 +767,7 @@ static int vmk80xx_alloc_usb_buffers(struct comedi_device *dev)
static int vmk80xx_init_subdevices(struct comedi_device *dev)
{
- const struct vmk80xx_board *boardinfo = comedi_board(dev);
+ const struct vmk80xx_board *boardinfo = dev->board_ptr;
struct vmk80xx_private *devpriv = dev->private;
struct comedi_subdevice *s;
int n_subd;